{ "id": "81773", "key": "TIMOB-5818", "fields": { "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": null, "resolutiondate": null, "created": "2011-10-20T12:09:41.000+0000", "epic": { "id": 170942, "key": "TIMOB-25710", "name": "SDK Parity effort", "summary": "SDK Parity effort", "color": { "key": "color_1" }, "done": false }, "priority": { "name": "Medium", "id": "3" }, "labels": [ "proxy", "ui", "view", "viewproxy" ], "versions": [ { "id": "11971", "description": "iOS5 and select Android fixes", "name": "Release 1.7.3", "archived": true, "released": true, "releaseDate": "2011-10-18" } ], "issuelinks": [ { "id": "57601", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "161046", "key": "TIMOB-23504", "fields": { "summary": "iOS: Titanium proxies don't extend Object.prototype properly", "status": { "description": "This issue is being actively worked on at the moment by the assignee.", "name": "In Progress", "id": "3", "statusCategory": { "id": 4, "key": "indeterminate", "colorName": "yellow", "name": "In Progress" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "57604", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "171652", "key": "TIMOB-26038", "fields": { "summary": "iOS: Move from legacy JavaScriptCore C Api to Obj-C API", "status": { "description": "This issue is being actively worked on at the moment by the assignee.", "name": "In Progress", "id": "3", "statusCategory": { "id": 4, "key": "indeterminate", "colorName": "yellow", "name": "In Progress" } }, "priority": { "name": "High", "id": "2" }, "issuetype": { "id": "6", "description": "gh.issue.epic.desc", "name": "Epic", "subtask": false } } } }, { "id": "56518", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "99720", "key": "TIMOB-10829", "fields": { "summary": "Android: Case of infinite loop", "status": { "description": "This issue was once resolved, but the resolution was deemed incorrect. From here issues are either marked assigned or resolved.", "name": "Reopened", "id": "4", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "priority": { "name": "Low", "id": "4" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } }, { "id": "56680", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "171876", "key": "TIMOB-26179", "fields": { "summary": "iOS: Property check on proxy always returns true", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Critical", "id": "1" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2019-04-26T19:04:12.000+0000", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "components": [ { "id": "10224", "name": "TiAPI", "description": "This component is used for cross-platform API work. Specifications are most likely to use this component." } ], "description": "Component: Ti API\r\n\r\nIf view proxies aren't going to behave like real JS objects (e.g. nested properties of proxy objects are immutable), and that isn't going to change, I propose we should develop a pure-JS API that wraps the proxies.\r\n\r\nI've begun wrapping Ti views in my [SproutCore-Titanium project|https://github.com/ebryn/sproutcore-titanium].\r\n\r\nLet's get a discussion started.", "attachment": [], "flagged": false, "summary": "Ti API: View proxies should behave like real JS objects - or they should be wrapped", "creator": { "name": "ebryn", "key": "ebryn", "displayName": "Erik Bryn", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "ebryn", "key": "ebryn", "displayName": "Erik Bryn", "active": true, "timeZone": "America/Los_Angeles" }, "environment": "Titanium Mobile 1.7.3", "comment": { "comments": [ { "id": "169908", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "Agreed - right now it is discouraged to add functionality to proxy objects, but the below is perfectly valid JavaScript:\r\n\r\n{code:javascript|title=example.js}\r\nvar view = Ti.UI.createView({height:50});\r\nview.foo = {};\r\nview.foo.bar = 'hello';\r\nview.foo.bar = 'goodbye';\r\n{code}\r\n\r\nProxy objects ideally should respect the rules of JavaScript. But if they do not, they should be wrapped in a JavaScript API we support. ", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2011-10-20T13:26:22.000+0000", "updated": "2011-10-20T13:26:22.000+0000" }, { "id": "170060", "author": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "body": "The issue is very nontrivial, especially because by design the proxy objects have to do things that Javascript was not designed for, such as multithreading and being accessible in multiple contexts. There are long-term designs in the works, but it requires extensive changes under and over the hood. For example, to move all the UI-reaching JS (IE, the JS that can access Ti.UI.foo) into a single thread, window.url would need to be dropped, and that does include rewriting KS, even.", "updateAuthor": { "name": "blainhamon", "key": "blainhamon", "displayName": "Blain Hamon", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-10-21T09:28:51.000+0000", "updated": "2011-10-21T09:28:51.000+0000" }, { "id": "171149", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "@Blain I don't doubt it would be non-trivial - however, having special objects that don't conform to the laws of JavaScript has caused many bugs in projects I and PS guys have worked on. If changing the behavior of proxy objects isn't an option, we should do something in JavaScript land to shield developers from the weirdness of these not-quite-objects. A thin shim layer of some kind, perhaps.", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2011-11-02T04:26:24.000+0000", "updated": "2011-11-02T04:26:24.000+0000" }, { "id": "171153", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "Kevin,\r\n\r\n(if I may add)\r\n\r\nthere are some attempts to solve lack of OOP features in Titanium that came from few community members. Some of them could be helpful in this case.\r\n\r\nBasically, they all are some kind of wrappers around Titanium components. One approach is to write wrappers that behave as proxies to Titanium objects. That wrappers are just native JS objects.\r\n\r\n\r\nSo ... for example:\r\n\r\n{code}\r\nfunction View(options) {\r\n this.Element = Ti.UI.createView(options);\r\n}\r\n\r\nView.prototype.add = function(TiObject) {\r\n this.Element.add(TiObject);\r\n};\r\n\r\n\r\nvar myView = new View({ height: 50 });\r\nmyView.add(Ti.UI.createButton({ title: 'Click me' });\r\n\r\n//now you can do this without a problem\r\nmyView.foo = {};\r\nmyView.foo.bar = 'hello';\r\nmyView.foo.bar = 'goodbye';\r\n{code}\r\n\r\n\r\nThis is a basic idea and it is OK in my opinion (but it needs more work to make it work as it should).\r\n\r\n\r\n\r\n\r\nI had similar idea, but I don't use wrappers as proxies (because I wanted to solve some other problems).\r\n\r\n\r\n\r\nAnyway, I hope this idea could be useful. If you need help or more info about this or other ideas, please let me know (or ask in Q/A).", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2011-11-02T05:52:32.000+0000", "updated": "2011-11-02T05:52:32.000+0000" }, { "id": "239797", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "Looking at this I'm not sure why this isn't working. Blain's comment about UI etc don't seem to make any sense to me.\n\nLike Kevin said, JS objects should act like JS objects and a viewproxy at the JS level should behave like other JS objects.\n\nI'm actually surprised this isn't the case.", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-26T15:00:55.000+0000", "updated": "2013-02-26T15:00:55.000+0000" }, { "id": "239798", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "can someone provide a very simple test case at the issue?", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-26T15:01:33.000+0000", "updated": "2013-02-26T15:01:33.000+0000" }, { "id": "239815", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "@Jeff\r\n\r\nhttps://gist.github.com/kwhinnery/5040513\r\n\r\n{code:javascript} \r\nvar w = Ti.UI.createWindow({\r\n\tbackgroundColor:'#fff'\r\n});\r\n\r\nvar l = Ti.UI.createLabel({\r\n\ttext:'click me',\r\n\tfont: {\r\n\t\tfontWeight:'bold',\r\n\t\tfontSize:24\r\n\t}\r\n});\r\nw.add(l);\r\n\r\nl.addEventListener('click', function(e) {\r\n\tl.text = 'clicked!'; // yep!\r\n\tl.font.fontSize = 12; // nope.\r\n});\r\n\r\nw.open();\r\n{code} ", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2013-02-26T17:54:07.000+0000", "updated": "2013-02-26T17:54:07.000+0000" }, { "id": "239816", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "thanks, that makes total since. \n\nthis should be rather easy to fix in the platform.\n\ni was confused my the immutable reference -- i think he was saying (now that i understand it) they are currently immutable, and they should be mutable (and he's correct).", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-26T18:03:50.000+0000", "updated": "2013-02-26T18:03:50.000+0000" }, { "id": "239817", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "On the plus side, this used to not work, but does now in 3.0:\r\n\r\n{code:javascript}\r\nvar db = Ti.Database.open('test');\r\n\r\ndb.execute('CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, foo TEXT);');\r\n\r\nvar args = [\r\n\t'INSERT INTO test(foo) VALUES (?)',\r\n\t'bar'\r\n];\r\n\r\n// This used to not work, but does in 3.0 for iOS!\r\ndb.execute.apply(db, args);\r\n\r\nTi.API.info('looping...');\r\nvar results = db.execute('SELECT * FROM test;');\r\n\r\nwhile(results.isValidRow()) {\r\n\tTi.API.info(results.fieldByName('foo'));\r\n\tresults.next();\r\n}\r\n\r\nresults.close();\r\ndb.close();\r\n{code}", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2013-02-26T18:04:24.000+0000", "updated": "2013-02-26T18:04:24.000+0000" }, { "id": "239970", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "This ticket actually dovetails quite nicely into TIMOB-12595. In fact, I would go so far as to say that they are probably dependent on each other.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-27T07:58:38.000+0000", "updated": "2013-02-27T07:58:38.000+0000" }, { "id": "239971", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Oh and also, if we do this right, we can do things like\n{code}\nvar button = Ti.UI.createButton();\nconsole.log(button instanceof Ti.UI.Button); // logs \"true\"\n{code}\nand\n{code}\nfunction myControl(){};\nmyControl.prototype = new Ti.UI.Button();\n// Add custom control stuff\n{code}", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-27T08:01:39.000+0000", "updated": "2013-02-27T08:01:39.000+0000" }, { "id": "240173", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "We also need to be able to do the following (based on syntax of ticket TIMOB-12595):\r\n\r\n{code}\r\nvar view = new Ti.UI.View();\r\n\r\nview.add = function(arguments) {\r\n alert('test');\r\n\r\n Ti.UI.View.add.apply(this, arguments);\r\n}\r\n{code}", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:20:54.000+0000", "updated": "2013-02-28T17:21:11.000+0000" }, { "id": "240174", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Too, this should not cause performance issues:\r\n\r\n{code}\r\nvar w = Ti.UI.createWindow({\r\n backgroundColor:'#fff'\r\n});\r\n \r\nvar l = Ti.UI.createLabel({\r\n text:'click me',\r\n customVarName: 'bla bla bla',\r\n font: {\r\n fontWeight:'bold',\r\n fontSize:24\r\n }\r\n});\r\nw.add(l);\r\n \r\nw.open();\r\n{code}\r\n\r\nRight now this is an issue because vars on a proxy object get passed to the native code, rather then having a whitelist of native properties on each object leaving the rest in JS land", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:24:31.000+0000", "updated": "2013-02-28T17:25:44.000+0000" }, { "id": "240177", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "I don't think we'll change the Factories into Classes that can be instantiated. We are using a Factory design pattern for Titanium and we're not going to be changing that anytime soon.\n\nSo, Ti.UI.createView() will be the way to instantiate a View object, not new Ti.UI.createView()", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:27:04.000+0000", "updated": "2013-02-28T17:27:04.000+0000" }, { "id": "240179", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "the problem is we have to pass to native land because you might need to reference those properties (if we are trying to make them full-fledged JS objects) in other functions in native land or in modules. i think we just need to improve the performance around this.. ", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:28:40.000+0000", "updated": "2013-02-28T17:28:40.000+0000" }, { "id": "240182", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Jeff That's fine, the ability to extend/replace methods and do instance of is far more important anyway", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:32:00.000+0000", "updated": "2013-02-28T17:32:00.000+0000" }, { "id": "240184", "author": { "name": "ebryn", "key": "ebryn", "displayName": "Erik Bryn", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Glad to see some movement around this finally. I ran into this issue with implementing bindings in views in ember-titanium.\r\n\r\nFWIW, I think the factory pattern is really ugly. I think allowing the use of the constructor functions would be great.", "updateAuthor": { "name": "ebryn", "key": "ebryn", "displayName": "Erik Bryn", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:32:19.000+0000", "updated": "2013-02-28T17:32:19.000+0000" }, { "id": "240186", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Jeff unless... and im just spit balling here... what if UI elements were wrapped in JS on the module level? Ti native modules support this, it would just need to be implemented... again just a thought.\r\n\r\nAll that would really be needed from an architecture standpoint would be for Titanium to implement JS Proxies like ecma 6 so that properties could be watched...", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:33:24.000+0000", "updated": "2013-02-28T17:36:23.000+0000" }, { "id": "240188", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "@Erik - this is a stylistic design item. some people love it, some people hate it. hard to please everyone in designing anything since mostly it's a matter of opinion vs. merit.\n\n@Matt - there may be some way to optimize this somehow, maybe using Bryan's new code processor, whereby we can be smart at when they need to cross the bridge. Maybe they could load from JSLand to nativeLand somehow \"on demand\" if only required and not passed to native bridge unless that is required. That might be something useful and not too hard to figure out.", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:38:31.000+0000", "updated": "2013-02-28T17:38:31.000+0000" }, { "id": "240195", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Jeff That would be great, in particular reducing the need to save properties like Ti.UI.SIZE to a var in JS land to prevent crossing the bridge with each use", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:46:15.000+0000", "updated": "2013-02-28T17:46:15.000+0000" }, { "id": "240196", "author": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Erik and @Jeff - Aside from the stylistic standpoint, forgetting a \"new\" is incredibly easy for developers to do and equally as difficult to identify based on runtime errors of which a developer may provide insufficient details.", "updateAuthor": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:47:07.000+0000", "updated": "2013-02-28T17:47:07.000+0000" }, { "id": "240199", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "@Tony - are we suggesting that you could either instantiate -or- use factory pattern?", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:49:21.000+0000", "updated": "2013-02-28T17:49:21.000+0000" }, { "id": "240200", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "If the UI were wrapped in JS as I suggested above... devs who like \"new\" better (such as myself) could easily add that syntax should they so choose.\r\n\r\nPlus, from a code structure standpoint, I should be able to extend a view to create a custom view... and for this I need a constructer method to do correctly.", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:50:11.000+0000", "updated": "2013-02-28T17:52:12.000+0000" }, { "id": "240201", "author": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@jeff - defending the factory pattern in that it can avoid dangers in code that are unique to languages like Javascript which will silently move on when a constructor is invoked in the absence of a \"new\". That's part of the reason Alloy has the \"create\" functions as well. Personally, I'm a long time strongly-typed OOP guy, so I prefer the \"new\" syntax. That said, I think the factory pattern better suits the mass usage of Titanium and its developers.", "updateAuthor": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:53:05.000+0000", "updated": "2013-02-28T17:53:05.000+0000" }, { "id": "240203", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "@Tony, @Matt - as long as we could support both styles, I would be fine with the change. The actual change to support a constructor in native is pretty ... we just can't break the API.", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:53:18.000+0000", "updated": "2013-02-28T17:53:18.000+0000" }, { "id": "240204", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "@Tony - Factory pattern is \"OO Design\" http://en.wikipedia.org/wiki/Factory_method_pattern -- especially useful when you're returning objects from an interface of an unknown type (for example, depends on the underlying platform object implementation). However, I can understand why devs also like \"new\" so they can create objects as well. I could go either way. If we can do both, i would be fine. The challenge will then be: when do you use which? (it could be a style thing, and maybe i'm OK with that).", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:57:02.000+0000", "updated": "2013-02-28T17:57:02.000+0000" }, { "id": "240205", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Jeff I 100% agree... it would suck to have that much of a breaking change. Even I, a fan of the constructer, would disagree with removing it all together (at least at first...)\r\n\r\nMy suggestion would allow for a more graceful removal over time, if removed at all", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T17:57:27.000+0000", "updated": "2013-02-28T17:58:13.000+0000" }, { "id": "240209", "author": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Jeff - haha, i guess citing OOP as my background was a poor way to phrase. I was referring more to the idea of manual class instantiation, personally preferring a constructor rather than a factory function. Alloy actually supports both now for its operations:\n\n{code:javascript}\nvar controller = Alloy.createController('someController', args);\n{code}\n\nis the same as \n\n{code:javascript}\nvar controller = new (require('alloy/controllers/someController'))(args);\n\n// or more verbosely, but easier to read\nvar Controller = require('alloy/controllers/someController');\nvar controller = new Controller(args);\n{code}\n\nBoth are perfectly valid code to see in a controller. The latter syntax is a little harder for devs to grasp since the generated modules are actually constructors, that is, the {{module.exports}} _is_ the constructor. It does however give me more confidence as a developer that I have total control of the instance. While Alloy.createController() does no additional operations to the instance, it's a layer of separation between me and the generated instance. The former syntax is a bit more clear and does not force developers to understand the underlying folder structure if they don't want.\n\nBut perhaps I'm just clouding the issue by mentioning Alloy as it is not subject to the same issues as are Titanium proxy objects. ", "updateAuthor": { "name": "tlukasavage", "key": "tlukasavage", "displayName": "Tony Lukasavage", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T18:09:10.000+0000", "updated": "2013-02-28T18:09:10.000+0000" }, { "id": "240212", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "One thing to keep in mind is that constructors in JavaScript are not special. They are just a function call with an implicit bind() and an implicit \"return this\". Basically this\r\n{code}\r\nfunction foo() {\r\n // constructor stuff\r\n}\r\nvar x = new foo();\r\n{code}\r\nis more or less evaluated as this\r\n{code}\r\nvar foo = function(){\r\n // constructor stuff\r\n return this;\r\n}.bind({});\r\nvar x = foo();\r\n{code}\r\n\r\nBasically what I'm saying is that the instantiation patter is very similar to the factory pattern in JavaScript, even if they don't appear that way on the surface", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T18:39:01.000+0000", "updated": "2013-02-28T18:39:27.000+0000" }, { "id": "240214", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Also, I don't think the factory pattern is especially useful in dynamically typed languages. The whole idea is you don't know what you are going to create, or who will create it, but really the factory pattern was introduced to get around the limitations in strongly typed languages where the full type chain has to be known in advance. This is a non-issue though in a dynamically typed language like JavaScript, so the usefulness of factory methods is reduced.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T18:46:50.000+0000", "updated": "2013-02-28T18:46:50.000+0000" }, { "id": "240250", "author": { "name": "rfranknj", "key": "rfranknj", "displayName": "Russell Frank", "active": true, "timeZone": "America/New_York" }, "body": "If I may - @Tony, it's fairly easy to detect if {{new}} was used on a constructor. If it wasn't, {{this}} will be the global object (or {{null}} in ES5 strict mode). So it's pretty easy to modify those constructors such that they can be used with or without {{new}}. \r\n\r\nReally, the native-binding-proxies should *never be exposed in the first place*. ES5 is powerful enough these days that simple JS proxies could be created that interface with the native-binding-proxies. In fact, they can be generated based on the JSCA (I think Matt did something like this already), and this is relatively easy to do. Then, you can do all sorts of fun things, like type checks on arguments, instanceof checks, and an app-level {{unhandledException}} event rather than that ugly \"Runtime Exception\" screen (by wrapping all added emitters). This can also reduce trips across the bridge. This is how NodeJS manages native bindings, and it makes a lot of sense; there's way more flexibility on the JS end, and we don't have to deal with strange native bindings that don't act like real JS objects.", "updateAuthor": { "name": "rfranknj", "key": "rfranknj", "displayName": "Russell Frank", "active": true, "timeZone": "America/New_York" }, "created": "2013-02-28T21:05:39.000+0000", "updated": "2013-02-28T21:05:39.000+0000" }, { "id": "240251", "author": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "body": "@russ- this is how android/V8 basically works today. there's always better ways of doing something after you've done it and we'll improve over time.", "updateAuthor": { "name": "jhaynie", "key": "jhaynie", "displayName": "Jeff Haynie", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T21:11:24.000+0000", "updated": "2013-02-28T21:11:24.000+0000" }, { "id": "240264", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "There is one caveat with checking {{this}}: the user can always do {{call}}, {{apply}}, or {{bind}}, which changes this.", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T22:06:10.000+0000", "updated": "2013-02-28T22:06:10.000+0000" }, { "id": "240269", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "FWIW this is an alternate mechanism if the API is defined in JS (which is a good idea):\r\n\r\nhttps://gist.github.com/kwhinnery/5059196", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2013-02-28T22:20:26.000+0000", "updated": "2013-02-28T22:20:26.000+0000" }, { "id": "240272", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "@Kevin That looks a little familiar https://github.com/appcelerator/titanium_mobile/blob/master/mobileweb/titanium/Ti/UI.js#L49 :)", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-02-28T22:30:18.000+0000", "updated": "2013-02-28T22:30:18.000+0000" }, { "id": "240356", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Honestly me and my team would be willing to do this... but I think the desire here would also be to rework the code to be more modular, thus outside the scope of what my team has the time to do.", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-03-01T14:24:08.000+0000", "updated": "2013-03-01T14:24:08.000+0000" }, { "id": "246155", "author": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "body": "As something to consider here.. this works on android (at least as of 3.1.0 preview) but not iOS:\r\n\r\n{code}\r\nvar win = Ti.UI.createWindow({\r\n open: function() {\r\n alert('test');\r\n }\r\n});\r\nwin.open(); // an alert is opened with test displayed on Android, on iOS nothing happens\r\n\r\n{code)\r\n\r\nHowever this still does not mean it supports prototype as:\r\n\r\n{code}\r\nwin.protoype;\r\n{code}\r\n\r\nis undefined\r\n", "updateAuthor": { "name": "mattapperson", "key": "mattapperson", "displayName": "me@gmail.com", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-04-06T16:42:06.000+0000", "updated": "2013-04-06T16:43:04.000+0000" }, { "id": "246387", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-04-08T09:39:53.000+0000", "updated": "2013-04-08T09:39:53.000+0000" }, { "id": "246421", "author": { "name": "ngupta", "key": "ngupta", "displayName": "Neeraj Gupta", "active": true, "timeZone": "America/Los_Angeles" }, "updateAuthor": { "name": "ngupta", "key": "ngupta", "displayName": "Neeraj Gupta", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2013-04-08T16:23:45.000+0000", "updated": "2013-04-08T16:23:45.000+0000" }, { "id": "246447", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "Thanks :)", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2013-04-08T17:56:33.000+0000", "updated": "2013-04-08T17:56:33.000+0000" }, { "id": "341140", "author": { "name": "yuchi", "key": "yuchi", "displayName": "Pier Paolo Ramon", "active": true, "timeZone": "Europe/Berlin" }, "body": "Another interesting issue related to this topic:\r\n\r\n{code:javascript}\r\n\r\nvar obj = {};\r\nvar label = Ti.UI.createLabel({ text: 'Some text' });\r\n\r\nprintPropertyDescriptor(label, 'text');\r\nprintPropertyDescriptor(label, 'idontexist');\r\nprintPropertyDescriptor(obj, 'idontexist');\r\n\r\nfunction printPropertyDescriptor(obj, name) {\r\n\tvar descriptor = Object.getOwnPropertyDescriptor(obj, 'clearTimeout');\r\n\tvar formatted = JSON.stringify(descriptor, null, 2);\r\n\tconsole.log(name + \" = \" + formatted);\r\n}\r\n{code}\r\n\r\nprints:\r\n\r\n{code}\r\n[INFO] : text = {\r\n[INFO] : \"writable\": false,\r\n[INFO] : \"enumerable\": false,\r\n[INFO] : \"configurable\": true\r\n[INFO] : }\r\n[INFO] : idontexist = {\r\n[INFO] : \"writable\": false,\r\n[INFO] : \"enumerable\": false,\r\n[INFO] : \"configurable\": true\r\n[INFO] : }\r\n[INFO] : idontexist = undefined\r\n{code}\r\n\r\nbut the expected result is\r\n\r\n{code}\r\n[INFO] : text = {\r\n[INFO] : \"writable\": false,\r\n[INFO] : \"enumerable\": false,\r\n[INFO] : \"configurable\": true,\r\n[INFO] : \"value\": 'Some text',\r\n[INFO] : }\r\n[INFO] : idontexist = undefined\r\n[INFO] : idontexist = undefined\r\n{code}\r\n\r\nSo {{Object.getOwnPropertyDescriptor}} for proxies returns *always* {{writable:false, enumerable:false, configurable:true}}.\r\n\r\nFunny.", "updateAuthor": { "name": "yuchi", "key": "yuchi", "displayName": "Pier Paolo Ramon", "active": true, "timeZone": "Europe/Berlin" }, "created": "2015-01-29T09:38:04.000+0000", "updated": "2015-01-29T09:38:04.000+0000" } ], "maxResults": 46, "total": 46, "startAt": 0 } } }