[Prototype-core] Re: A more efficient $super for Prototype 2
On Tuesday 08 September 2009 16:18:20 T.J. Crowder wrote: @Jim, Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. I have a hunch we could get function names in the same way that we implement Function#argumentNames. A regex on the toString. -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Wednesday 09 September 2009 09:02:28 Jim Higson wrote: I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. I have a hunch we could get function names in the same way that we implement Function#argumentNames. A regex on the toString. I should have looked first - this is function decompilation and considered a bad thing. -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi all, I thought of a wrinkle today: Mixins. This new mechanism modifies function instances if they override base class functions (it leaves them alone if they don't). So if you mix in something that has a function with the same name as a parent class's function, we will set a $super property on the mixin function's instance. That seems wrong to me, mixins should be read-only as far as the mechanism is concerned, IMHO. Now, in _practical_ terms, unless the mixin function calls $super (which seems an odd thing for a mixin to do, but I can come up with an edge case use case for it), it doesn't matter much. But if A) the mixin function does (presumably optionally) call $super, and B) more than one class mixes the mixin in, AND C) the mixin overrides one of the functions in at least one of those classes, you get class crosstalk -- a very bad thing. My first thought for how to deal with this was stupid and I'll spare you. My *second* (hopefully not stupid) thought was to mark mixin functions with a property telling us to leave them alone. I see two ramifications to doing that: 1. An API change: To define a mixin, you'd ideally want to run it through something (something we'd presumably provide) that spins through and marks the functions so we leave them alone. var MyMixIn = Class.createMixin(...); 2. Mixins can't even optionally participate in supercalls, which they can with the current mechanism. Now, for me, #2 is not a problem. I'm not thrilled about introducing #1, although really you only have to do that to protect against an edge case you're probably not going to run into. It's someting a library of mixins would want to be sure to do, but within a non- library project, not sure it really matters. -- T.J. On Sep 9, 9:28 am, Jim Higson j...@wikizzle.org wrote: On Wednesday 09 September 2009 09:02:28 Jim Higson wrote: I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. I have a hunch we could get function names in the same way that we implement Function#argumentNames. A regex on the toString. I should have looked first - this is function decompilation and considered a bad thing. -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
TJ, I don't particularly think this is a problem or even a new problem (wouldn't the current let you do this as well?). This sounds like protecting the developer from themselves. I think as long as you sufficiently state what will happen in a particular instance then it is perfectly reasonable to allow each individual developer to handle it as they see fit. Allen Madsen http://www.allenmadsen.com On Wed, Sep 9, 2009 at 7:29 AM, T.J. Crowdert...@crowdersoftware.com wrote: Hi all, I thought of a wrinkle today: Mixins. This new mechanism modifies function instances if they override base class functions (it leaves them alone if they don't). So if you mix in something that has a function with the same name as a parent class's function, we will set a $super property on the mixin function's instance. That seems wrong to me, mixins should be read-only as far as the mechanism is concerned, IMHO. Now, in _practical_ terms, unless the mixin function calls $super (which seems an odd thing for a mixin to do, but I can come up with an edge case use case for it), it doesn't matter much. But if A) the mixin function does (presumably optionally) call $super, and B) more than one class mixes the mixin in, AND C) the mixin overrides one of the functions in at least one of those classes, you get class crosstalk -- a very bad thing. My first thought for how to deal with this was stupid and I'll spare you. My *second* (hopefully not stupid) thought was to mark mixin functions with a property telling us to leave them alone. I see two ramifications to doing that: 1. An API change: To define a mixin, you'd ideally want to run it through something (something we'd presumably provide) that spins through and marks the functions so we leave them alone. var MyMixIn = Class.createMixin(...); 2. Mixins can't even optionally participate in supercalls, which they can with the current mechanism. Now, for me, #2 is not a problem. I'm not thrilled about introducing #1, although really you only have to do that to protect against an edge case you're probably not going to run into. It's someting a library of mixins would want to be sure to do, but within a non- library project, not sure it really matters. -- T.J. On Sep 9, 9:28 am, Jim Higson j...@wikizzle.org wrote: On Wednesday 09 September 2009 09:02:28 Jim Higson wrote: I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. I have a hunch we could get function names in the same way that we implement Function#argumentNames. A regex on the toString. I should have looked first - this is function decompilation and considered a bad thing. -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
I'm with Allen on this. I don't think it's uncommon for mixins to want to hook into existing functionality. This is trivial if they can invoke $super (the original object's method), and problematic otherwise. To give a concrete example, a while ago I implemented a Selectable mixin for some collection classes. Because this mixin maintained the selection state in a private cache, it needed to hook into the remove() method to allow it to properly update the cache. Thus, I could easily see doing something like this: var Selectable = Class.createMixin({ // Various methods we add to the collection class... selectItem: function(item){...}, deselectItem:function(item){...}, getSelectedItems: function() {...}, // Make sure we deselect items before they're removed remove: function($super, item) { this.deselectItem(item); $super(item); } }) On Wed, Sep 9, 2009 at 7:31 AM, Allen Madsen bla...@gmail.com wrote: TJ, I don't particularly think this is a problem or even a new problem (wouldn't the current let you do this as well?). This sounds like protecting the developer from themselves. I think as long as you sufficiently state what will happen in a particular instance then it is perfectly reasonable to allow each individual developer to handle it as they see fit. Allen Madsen http://www.allenmadsen.com --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Allen, Thanks. I agree, it's a very edgy edge case. :-) (wouldn't the current let you do this as well?) Actually, it works in the current implementation, because if a mixin function uses $super (which again is a bit odd), addMethods wraps it up in a closure and never modifies the actual function. The closure is specific to the subclass, and so it all Just Works. -- T.J. On Sep 9, 3:31 pm, Allen Madsen bla...@gmail.com wrote: TJ, I don't particularly think this is a problem or even a new problem (wouldn't the current let you do this as well?). This sounds like protecting the developer from themselves. I think as long as you sufficiently state what will happen in a particular instance then it is perfectly reasonable to allow each individual developer to handle it as they see fit. Allen Madsenhttp://www.allenmadsen.com On Wed, Sep 9, 2009 at 7:29 AM, T.J. Crowdert...@crowdersoftware.com wrote: Hi all, I thought of a wrinkle today: Mixins. This new mechanism modifies function instances if they override base class functions (it leaves them alone if they don't). So if you mix in something that has a function with the same name as a parent class's function, we will set a $super property on the mixin function's instance. That seems wrong to me, mixins should be read-only as far as the mechanism is concerned, IMHO. Now, in _practical_ terms, unless the mixin function calls $super (which seems an odd thing for a mixin to do, but I can come up with an edge case use case for it), it doesn't matter much. But if A) the mixin function does (presumably optionally) call $super, and B) more than one class mixes the mixin in, AND C) the mixin overrides one of the functions in at least one of those classes, you get class crosstalk -- a very bad thing. My first thought for how to deal with this was stupid and I'll spare you. My *second* (hopefully not stupid) thought was to mark mixin functions with a property telling us to leave them alone. I see two ramifications to doing that: 1. An API change: To define a mixin, you'd ideally want to run it through something (something we'd presumably provide) that spins through and marks the functions so we leave them alone. var MyMixIn = Class.createMixin(...); 2. Mixins can't even optionally participate in supercalls, which they can with the current mechanism. Now, for me, #2 is not a problem. I'm not thrilled about introducing #1, although really you only have to do that to protect against an edge case you're probably not going to run into. It's someting a library of mixins would want to be sure to do, but within a non- library project, not sure it really matters. -- T.J. On Sep 9, 9:28 am, Jim Higson j...@wikizzle.org wrote: On Wednesday 09 September 2009 09:02:28 Jim Higson wrote: I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. I have a hunch we could get function names in the same way that we implement Function#argumentNames. A regex on the toString. I should have looked first - this is function decompilation and considered a bad thing. -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Sep 9, 7:29 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi all, I thought of a wrinkle today: Mixins. This new mechanism modifies function instances if they override base class functions (it leaves them alone if they don't). So if you mix in something that has a function with the same name as a parent class's function, we will set a $super property on the mixin function's instance. That seems wrong to me, mixins should be read-only as far as the mechanism is concerned, IMHO. Now, in _practical_ terms, unless the mixin function calls $super (which seems an odd thing for a mixin to do, but I can come up with an edge case use case for it), it doesn't matter much. But if A) the mixin function does (presumably optionally) call $super, and B) more than one class mixes the mixin in, AND C) the mixin overrides one of the functions in at least one of those classes, you get class crosstalk -- a very bad thing. My first thought for how to deal with this was stupid and I'll spare you. My *second* (hopefully not stupid) thought was to mark mixin functions with a property telling us to leave them alone. I see two ramifications to doing that: Well, technically mixins are already marked by being an object, rather than a function :) // Constructor/Class (a function) function Person(){} // Mixin (not a function, although it could be (!)) var Observable = { observe: function(){ ... }, stopObserving: function(){ ... } } I don't think there was ever such requirement for mixins in Prototype, though, so there's a chance people are using function-based mixins (for whatever reasons): function Observable(){ ... }; Object.extend(Observable, { observe: function(){ ... }, stopObserving: function(){ ... } }); [...] -- kangax --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Robert, That's a very interesting use case, thanks for that. I can certainly see the utility of that, and in fact as I was writing all of this up for my (pathetic little) blog I was getting increasingly uncomfortable with the mixin issue. If it's important for mixins to participate in hierarchy, it occurs to me that my second point (saying they can't) is unduly pessimistic. Of course they can. Unlike subclass methods, it's important that we don't modify them directly, but that doesn't mean they can't play. In this one special case where we basically have no choice, we can allow ourselves the indirection and wrap them, modifying the wrapper rather than the original. That costs a closure per mixin method (not on every call, just at mixin-time), and then an extra #apply on each mixin call. Still much more efficient than what we currently have, and it keeps mixins fully able to participate in the hierarchy. That's much more satisfying that shutting them out (and potentially breaking the chain). Thanks again, -- T.J. On Sep 9, 4:00 pm, Robert Kieffer bro...@gmail.com wrote: I'm with Allen on this. I don't think it's uncommon for mixins to want to hook into existing functionality. This is trivial if they can invoke $super (the original object's method), and problematic otherwise. To give a concrete example, a while ago I implemented a Selectable mixin for some collection classes. Because this mixin maintained the selection state in a private cache, it needed to hook into the remove() method to allow it to properly update the cache. Thus, I could easily see doing something like this: var Selectable = Class.createMixin({ // Various methods we add to the collection class... selectItem: function(item){...}, deselectItem:function(item){...}, getSelectedItems: function() {...}, // Make sure we deselect items before they're removed remove: function($super, item) { this.deselectItem(item); $super(item); } }) On Wed, Sep 9, 2009 at 7:31 AM, Allen Madsen bla...@gmail.com wrote: TJ, I don't particularly think this is a problem or even a new problem (wouldn't the current let you do this as well?). This sounds like protecting the developer from themselves. I think as long as you sufficiently state what will happen in a particular instance then it is perfectly reasonable to allow each individual developer to handle it as they see fit. Allen Madsen http://www.allenmadsen.com --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Tuesday 08 September 2009 03:57:13 Allen Madsen wrote: TJ, I guess I don't understand why it wouldn't work. I'll illustrate how I understand it and you correct me where I'm wrong. var A = Class.create({ nifty: function(){} }); var B = Class.create(A, { nifty: function(){ this.nifty.$super(); // refers to A.nifty() //this.nifty(); //would cause recursion } }); Wouldn't you have to do this to preserve scope? this.nifty.$super.call( this ); Myself, I've never liked the .call syntax much because I mistake it with apply: the two words seem arbitrary. But, yeah, I can see that pre-binding every overridden method of every object would be a big overhead. Perhaps I would do: var B = Class.create(A, { nifty: function(){ var $super = this.nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } }); [1] Please correct if this is wrong! -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Jim, Perhaps I would do: var B = Class.create(A, { nifty: function(){ var $super = this.nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } }); [1] Please correct if this is wrong! You need to leave out the this. and use a named function instead; see my note to Allen for the details. You can use #bind if you want to, but in my experience you're typically only making a single call to the superclass method, so it's not really worth the overhead. But here's what it would look like: var B = Class.create(A, (function(){ function nifty(){ var $super = nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } return {nifty: nifty}; })()); -- T.J. On Sep 8, 8:52 am, Jim Higson j...@wikizzle.org wrote: On Tuesday 08 September 2009 03:57:13 Allen Madsen wrote: TJ, I guess I don't understand why it wouldn't work. I'll illustrate how I understand it and you correct me where I'm wrong. var A = Class.create({ nifty: function(){} }); var B = Class.create(A, { nifty: function(){ this.nifty.$super(); // refers to A.nifty() //this.nifty(); //would cause recursion } }); Wouldn't you have to do this to preserve scope? this.nifty.$super.call( this ); Myself, I've never liked the .call syntax much because I mistake it with apply: the two words seem arbitrary. But, yeah, I can see that pre-binding every overridden method of every object would be a big overhead. Perhaps I would do: var B = Class.create(A, { nifty: function(){ var $super = this.nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } }); [1] Please correct if this is wrong! -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
It really looks nicer :) I was generally using this.constructor ... and so on. But this is better. I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) arguments.callee.$supper.call(this, ...) Witch is nice. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
2009/9/8 T.J. Crowder t...@crowdersoftware.com: Hi all, I've taken a break from porting documentation from Mephisto into the source (zz) to do a first take on implementing the new supercalls! Here's the commit in a branch in my repo:[1] That commit includes the code, documentation, and unit tests. The old class unit tests are still there (I've just renamed them oldclass, though not properly from a git history POV I just realized) so we continue to test the old style until we remove it, which I would assume would be a couple of versions after introducing the new one. I've also added tests to prove that you can mix the two styles (derive from an old-style using the new style, or vice-versa), not that I recommend doing that. Apologies in advance if I'm out on a limb stylistically; I tried to fit in (inline vars! yuck!). If I've gone astray, please let me know. As you can see, the implementation in the Prototype code is dead simple, and yet the new supercalls are easy to use, particularly if you're already sold on the benefits of using named rather than anonymous functions (or if you don't care how phenomenally slow `arguments.callee` is). This gist[2] contains a basic performance comparison page. The change really is dramatic, even if you use arguments.callee -- but it's mind- blowing if you use named functions (thanks, kangax, for pointing that out!). About dynamism: Coming from the compiled language world, I would never have thought to handle people adding methods to classes on-the- fly AFTER the class may have been derived; thank you to Tobie for pointing out that requirement. The code correctly handles defining new methods and redefining methods, ensuring that everybody is linked up correctly. (That turned out to be trivial.) But I have a couple of questions for you dynamic types: 1) Does it need to support _removing_ a method entirely? (Currently does not; easy to add.) 2) Does it need to handle edge cases where a name is defined on classes but is not a function (e.g., a class variable), but then we REdefine it to be a function? Or vice-versa (replacing a function with a non-function)? (Currently does not handle it; will complicate the code somewhat.) I can just about imagine (1), but frankly if you're doing (2) I think you need to revisit what you're doing! :-) [1] http://github.com/tjcrowder/prototype/commit/79d3e1dfd32220299f0a5aceacfc6fd3ffa2a089 [2] http://gist.github.com/182817 Comments/suggestions/jeers welcome. (Well, no, not jeers.) -- T.J. On Sep 8, 9:28 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi Jim, Perhaps I would do: var B = Class.create(A, { nifty: function(){ var $super = this.nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } }); [1] Please correct if this is wrong! You need to leave out the this. and use a named function instead; see my note to Allen for the details. You can use #bind if you want to, but in my experience you're typically only making a single call to the superclass method, so it's not really worth the overhead. But here's what it would look like: var B = Class.create(A, (function(){ function nifty(){ var $super = nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } return {nifty: nifty}; })()); -- T.J. On Sep 8, 8:52 am, Jim Higson j...@wikizzle.org wrote: On Tuesday 08 September 2009 03:57:13 Allen Madsen wrote: TJ, I guess I don't understand why it wouldn't work. I'll illustrate how I understand it and you correct me where I'm wrong. var A = Class.create({ nifty: function(){} }); var B = Class.create(A, { nifty: function(){ this.nifty.$super(); // refers to A.nifty() //this.nifty(); //would cause recursion } }); Wouldn't you have to do this to preserve scope? this.nifty.$super.call( this ); Myself, I've never liked the .call syntax much because I mistake it with apply: the two words seem arbitrary. But, yeah, I can see that pre-binding every overridden method of every object would be a big overhead. Perhaps I would do: var B = Class.create(A, { nifty: function(){ var $super = this.nifty.$super.bind( this ); // $super refers to A.nifty() bound to this $super(); } }); [1] Please correct if this is wrong! -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ I'm getting an error in Chrome when I click Test functionality ... Test loops: (suggest about 5,000 for IE, 200,000 for Chrome, 100,000 for Firefox or Safari) GOOD: OP(hi) GOOD: OP(hi) OC GOOD: OP(hi) OC OGC GOOD: NP(hi) Exception: TypeError: Cannot call method 'call' of undefined In FireFox ... Test loops: (suggest about 5,000 for IE, 200,000 for Chrome, 100,000 for Firefox or Safari) GOOD: OP(hi) GOOD: OP(hi) OC
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi, It really looks nicer :) Thanks! I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) No, you need to drop the this. from the beginning of that. See my reply to Allen a couple up (or the PDoc comments here[1]) for why. arguments.callee.$supper.call(this, ...) Yup, that works (assuming $super rather than $supper), although it's a lot slower than using the function name. It's still markedly faster than the current mechanism. -- T.J. :-) On Sep 8, 11:20 am, Radoslav Stankov rstan...@gmail.com wrote: It really looks nicer :) I was generally using this.constructor ... and so on. But this is better. I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) arguments.callee.$supper.call(this, ...) Witch is nice. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
2009/9/8 T.J. Crowder t...@crowdersoftware.com: Hi, It really looks nicer :) Thanks! I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) No, you need to drop the this. from the beginning of that. See my reply to Allen a couple up (or the PDoc comments here[1]) for why. arguments.callee.$supper.call(this, ...) Yup, that works (assuming $super rather than $supper), although it's a lot slower than using the function name. It's still markedly faster than the current mechanism. -- T.J. :-) On Sep 8, 11:20 am, Radoslav Stankov rstan...@gmail.com wrote: It really looks nicer :) I was generally using this.constructor ... and so on. But this is better. I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) arguments.callee.$supper.call(this, ...) Witch is nice. In the end I downloaded the archive and used src to rebuild a new prototype. Chrome... test loops: 50 Old mechanism time: 9666ms New mechanism time: 639ms *** The test was a bit short, the timing data may be suspect; try more loops. Improvement: 93.39%, e.g., old takes 15.13 times as long as new. A bit short Half a million loops and it's a bit short -- - Richard Quadling Standing on the shoulders of some very clever giants! EE : http://www.experts-exchange.com/M_248814.html Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498r=213474731 ZOPA : http://uk.zopa.com/member/RQuadling --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Richard, You want to use the supercalls branch; I suspect you used master. This should do it: git clone git://github.com/tjcrowder/prototype.git git checkout supercalls rake dist In any case, I see you got there in the end. A bit short Half a million loops and it's a bit short Heh heh heh. Yeah, well, we wouldn't want to jump to conclusions based on insufficient test data. :-) I have it print that out if the total test time was less than 15 seconds. Only a 15X improvement on Chrome, eh? I've seen it even higher than that... -- T.J. :-) On Sep 8, 11:32 am, Richard Quadling rquadl...@googlemail.com wrote: 2009/9/8 T.J. Crowder t...@crowdersoftware.com: Hi, It really looks nicer :) Thanks! I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) No, you need to drop the this. from the beginning of that. See my reply to Allen a couple up (or the PDoc comments here[1]) for why. arguments.callee.$supper.call(this, ...) Yup, that works (assuming $super rather than $supper), although it's a lot slower than using the function name. It's still markedly faster than the current mechanism. -- T.J. :-) On Sep 8, 11:20 am, Radoslav Stankov rstan...@gmail.com wrote: It really looks nicer :) I was generally using this.constructor ... and so on. But this is better. I haven't run it but I guest it is possible to do this.method.$super.call(this, ...) arguments.callee.$supper.call(this, ...) Witch is nice. In the end I downloaded the archive and used src to rebuild a new prototype. Chrome... test loops: 50 Old mechanism time: 9666ms New mechanism time: 639ms *** The test was a bit short, the timing data may be suspect; try more loops. Improvement: 93.39%, e.g., old takes 15.13 times as long as new. A bit short Half a million loops and it's a bit short -- - Richard Quadling Standing on the shoulders of some very clever giants! EE :http://www.experts-exchange.com/M_248814.html Zend Certified Engineer :http://zend.com/zce.php?c=ZEND002498r=213474731 ZOPA :http://uk.zopa.com/member/RQuadling --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi all, Just validated Radoslav's steps, and they work (provided you add the submodules stuff), although it takes a while because you have to retrieve everything (including submodules). Instead, it's really easy and very fast to just add my repo as a remote within your existing local prototype repo, and the pull the supercalls stuff into a branch: 1. Get into your local prototype repo 2. Add mine as a remote source: git remote add tjcrowder git://github.com/tjcrowder/prototype.git 3. Create and switch to a local supercalls branch git branch supercalls git checkout supercalls 4. Pull my stuff into it: git pull tjcrowder supercalls 5. Build rake dist 6. Profit! Alternately, here's[1] a pre-baked copy for anyone who just wants to grab it and play around, but of course it will go stale fairly quickly. [1] http://gist.github.com/182838 -- T.J. On Sep 8, 1:15 pm, T.J. Crowder t...@crowdersoftware.com wrote: Hi Radoslav, There must be a smarter way with this, but I'm still a git newbie. Hey, you're better at it than I am. :-) Bw, this worked fine, since $super is attached to function It only worked because you only had a Parent Child hierarchy. As soon as you throw a third level into it (the grandchild test), e.g. Parent Child GrandChild, if any of the middle layers (Child, in this case) tries to do a supercall, it will *endlessly recurse*. Really. Again, please read my reply to Allen above[1] for details. [1]http://groups.google.com/group/prototype-core/browse_thread/thread/db... -- T.J. On Sep 8, 1:03 pm, Radoslav Stankov rstan...@gmail.com wrote: git pull origin supercalls is needed for getting not only the master branch. So we have: git clone git://github.com/tjcrowder/prototype.git cd prototype git branch supercalls git checkout supercalls git pull origin supercalls rake dist There must be a smarter way with this, but I'm still a git newbie. Bw, this worked fine, since $super is attached to function pre var SuperKlass = Class.create({ update: function(){ console.log('super'); } }); // written also as var SuperKlass = Class.create((function(){ function update(){ console.log('super'); } return {update: update}; })()); var SubKlass = Class.create(SuperKlass, { update: function(){ this.update.$super.call(this); console.log('sub'); } }); (new SubKlass()).update() /pre p.s. on my MacOX Leopard, it behaves very good Safari4: test loops: 10 Old mechanism time: 686ms New mechanism time: 123ms Firefox 3.5 test loops: 10 Old mechanism time: 14868ms New mechanism time: 442ms --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding callee), it would be nice if defining that was simplified. So something like: var A = Class.create({ nifty: function(){} }); var B = Class.create(A, function(){ function nifty(){ nifty.$super.call(this); } return {nifty: nifty}; }); Allen Madsen http://www.allenmadsen.com On Tue, Sep 8, 2009 at 8:34 AM, T.J. Crowder t...@crowdersoftware.com wrote: Hi all, Just validated Radoslav's steps, and they work (provided you add the submodules stuff), although it takes a while because you have to retrieve everything (including submodules). Instead, it's really easy and very fast to just add my repo as a remote within your existing local prototype repo, and the pull the supercalls stuff into a branch: 1. Get into your local prototype repo 2. Add mine as a remote source: git remote add tjcrowder git://github.com/tjcrowder/prototype.git 3. Create and switch to a local supercalls branch git branch supercalls git checkout supercalls 4. Pull my stuff into it: git pull tjcrowder supercalls 5. Build rake dist 6. Profit! Alternately, here's[1] a pre-baked copy for anyone who just wants to grab it and play around, but of course it will go stale fairly quickly. [1] http://gist.github.com/182838 -- T.J. On Sep 8, 1:15 pm, T.J. Crowder t...@crowdersoftware.com wrote: Hi Radoslav, There must be a smarter way with this, but I'm still a git newbie. Hey, you're better at it than I am. :-) Bw, this worked fine, since $super is attached to function It only worked because you only had a Parent Child hierarchy. As soon as you throw a third level into it (the grandchild test), e.g. Parent Child GrandChild, if any of the middle layers (Child, in this case) tries to do a supercall, it will *endlessly recurse*. Really. Again, please read my reply to Allen above[1] for details. [1] http://groups.google.com/group/prototype-core/browse_thread/thread/db... -- T.J. On Sep 8, 1:03 pm, Radoslav Stankov rstan...@gmail.com wrote: git pull origin supercalls is needed for getting not only the master branch. So we have: git clone git://github.com/tjcrowder/prototype.git cd prototype git branch supercalls git checkout supercalls git pull origin supercalls rake dist There must be a smarter way with this, but I'm still a git newbie. Bw, this worked fine, since $super is attached to function pre var SuperKlass = Class.create({ update: function(){ console.log('super'); } }); // written also as var SuperKlass = Class.create((function(){ function update(){ console.log('super'); } return {update: update}; })()); var SubKlass = Class.create(SuperKlass, { update: function(){ this.update.$super.call(this); console.log('sub'); } }); (new SubKlass()).update() /pre p.s. on my MacOX Leopard, it behaves very good Safari4: test loops: 10 Old mechanism time: 686ms New mechanism time: 123ms Firefox 3.5 test loops: 10 Old mechanism time: 14868ms New mechanism time: 442ms --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Oh, also, you may want to throw something into update helper about your new method of getting super. Allen Madsen http://www.allenmadsen.com On Tue, Sep 8, 2009 at 9:56 AM, Allen Madsen bla...@gmail.com wrote: Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding callee), it would be nice if defining that was simplified. So something like: var A = Class.create({ nifty: function(){} }); var B = Class.create(A, function(){ function nifty(){ nifty.$super.call(this); } return {nifty: nifty}; }); Allen Madsen http://www.allenmadsen.com On Tue, Sep 8, 2009 at 8:34 AM, T.J. Crowder t...@crowdersoftware.comwrote: Hi all, Just validated Radoslav's steps, and they work (provided you add the submodules stuff), although it takes a while because you have to retrieve everything (including submodules). Instead, it's really easy and very fast to just add my repo as a remote within your existing local prototype repo, and the pull the supercalls stuff into a branch: 1. Get into your local prototype repo 2. Add mine as a remote source: git remote add tjcrowder git://github.com/tjcrowder/prototype.git 3. Create and switch to a local supercalls branch git branch supercalls git checkout supercalls 4. Pull my stuff into it: git pull tjcrowder supercalls 5. Build rake dist 6. Profit! Alternately, here's[1] a pre-baked copy for anyone who just wants to grab it and play around, but of course it will go stale fairly quickly. [1] http://gist.github.com/182838 -- T.J. On Sep 8, 1:15 pm, T.J. Crowder t...@crowdersoftware.com wrote: Hi Radoslav, There must be a smarter way with this, but I'm still a git newbie. Hey, you're better at it than I am. :-) Bw, this worked fine, since $super is attached to function It only worked because you only had a Parent Child hierarchy. As soon as you throw a third level into it (the grandchild test), e.g. Parent Child GrandChild, if any of the middle layers (Child, in this case) tries to do a supercall, it will *endlessly recurse*. Really. Again, please read my reply to Allen above[1] for details. [1] http://groups.google.com/group/prototype-core/browse_thread/thread/db... -- T.J. On Sep 8, 1:03 pm, Radoslav Stankov rstan...@gmail.com wrote: git pull origin supercalls is needed for getting not only the master branch. So we have: git clone git://github.com/tjcrowder/prototype.git cd prototype git branch supercalls git checkout supercalls git pull origin supercalls rake dist There must be a smarter way with this, but I'm still a git newbie. Bw, this worked fine, since $super is attached to function pre var SuperKlass = Class.create({ update: function(){ console.log('super'); } }); // written also as var SuperKlass = Class.create((function(){ function update(){ console.log('super'); } return {update: update}; })()); var SubKlass = Class.create(SuperKlass, { update: function(){ this.update.$super.call(this); console.log('sub'); } }); (new SubKlass()).update() /pre p.s. on my MacOX Leopard, it behaves very good Safari4: test loops: 10 Old mechanism time: 686ms New mechanism time: 123ms Firefox 3.5 test loops: 10 Old mechanism time: 14868ms New mechanism time: 442ms --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Tuesday 08 September 2009 15:27:49 Allen Madsen wrote: Jim, I like your suggestion, except that there would be no way to create private variables and functions that could be used in more than one function. For example, with my suggested method I could do: I suppose if you wanted both you could say named functions get added to the class as a method, whereas the object result of executing anon functions get added. Over complicated? -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
I still have some serious reservations about this patch. Before I dive into details, though, can someone please tell me why we're not looking at Dean Edwards old Base2 approach[1], or John Resig's variation on that[2]? That general approach would seem to offer a good trade-off between performance and usability. ... and it's that trade-off I have reservations about. If Prototype is going to replace the current $super technique, it's this tradeoff that I would like to see a nice balance on. And with all respect to you, T.J., I don't think your solution has that. There's no question it is more performant (woot!), but I have serious doubts about it's overall usability. The requirement for named function expressions (NFEs) puts a serious crimp in developers coding style. Having to declare the functions in one section and then wrap them up in a returned data structure in another... It's nice that this style works for Prototype, and I appreciate the advantages, but it's not exactly commonplace (not that anything is). It'll definitely give more than one developer pause. Can I politely suggest that maybe you guys are a bit too close to the code and are taking the learning curve here for granted? And having to explicitly type the name of each function 3-4 times to define it will very quickly get tiresome. It makes writing code harder, and it makes refactoring it harder as well. Which means more prone to error; there is still no IDE that is able to automatically and accurately change the name of functions when declared like this. With all the drum-beating around here about code maintainability, I'm a little surprised to see this issue treated so lightly. Most importantly, the syntax for invoking a supermethod, while not quite as horrid as some others we've seen and discussed, is still not that great. I mean, come on, close your eyes, take a few deep breaths, and then look at it... nifty.$super.call(this, spiffy) ... .vs. the current style: $super(spiffy) ... or what the Dean Edwards/John Resig style: this._super(spiffy) I know, I know, the current style has performance issues. But for a lot of developers a simpler, less confusing syntax will trump that. I suspect most will continue to use the old $super scheme, which will make it much harder to deprecate than you might expect. And if the old $super scheme is gonna stick around for a while because the new scheme ain't good enough, than at the end of the day this new code is just unnecessary code bloat. Certainly Prototype itself doesn't need it - the Ajax.* classes and Timed Observer aren't used in situations where $super is called so often that the incremental performance improvement will make a difference. Sorry, I probably should have posted this before you spent your time implementing your patch. Still... I hope this is a constructive gut check for folks. - rwk [1] http://dean.edwards.name/weblog/2006/03/base/ [2] http://ejohn.org/blog/simple-javascript-inheritance/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
@Allen, For your two suggested additions. I don't think I have ever had a use for either. Thanks. One thing I would like to suggest though is that Class.create take an object or a function as an argument. I _really_ like that idea, not least because it seems to me that by reducing the *seeming* complexity it makes it much easier for relative novices to adopt using named functions. But unfortunately it would a further API change, because otherwise Class.create can't tell whether the first argument is a base class constructor or a function you want it to call to retrieve the members object: var X = Class.create(BaseClass); var Y = Class.create(function() { function nifty() { ... } return {nifty: nifty}; }); You see the problem. The API change wouldn't need to be large, it's just suddenly we're impacting the API more than we otherwise have to, and my gut reaction to that is usually caution (not least because unless I caution myself, I get a bit change-happy). None of which is meant to say A) That I'd be opposed to it if a bunch of smart people said it was worth it (quite the opposite, in fact); or B) That I'm not going to *immediately* steal your idea for my own projects. :-) FWIW, and there are 18 ways to skin this cat, but if we did anything I'd prefer to leave Class.create alone, but I'd be really interested in the idea of providing a new entry point (Class.define, perhaps) that provides this new functionality and which solves the problem of how to specify the base class in some clever way. Perhaps a new thread for this sub-topic? @Jim, Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. -- T.J. :-) On Sep 8, 3:27 pm, Allen Madsen bla...@gmail.com wrote: Jim, I like your suggestion, except that there would be no way to create private variables and functions that could be used in more than one function. For example, with my suggested method I could do: Var A = Class.create(function(){ var privateVar = 0; function privateFunction(){} function nifty(){ privateFunction(); privateVar = 3; } return {nifty: nifty}; }); I'd much rather see it in this form. Allen Madsenhttp://www.allenmadsen.com On Tue, Sep 8, 2009 at 10:12 AM, Jim Higson j...@wikizzle.org wrote: On Tuesday 08 September 2009 14:56:06 Allen Madsen wrote: Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding callee), it would be nice if defining that was simplified. So something like: var A = Class.create({ nifty: function(){} }); var B = Class.create(A, function(){ function nifty(){ nifty.$super.call(this); } return {nifty: nifty}; }); How about simplifying further: var B = Class.create( A, function nifty(){ nifty.$super.call(this); } , function alsoNifty(){ this.nifty(); } ); Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Tuesday 08 September 2009 14:56:06 Allen Madsen wrote: Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding callee), it would be nice if defining that was simplified. So something like: var A = Class.create({ nifty: function(){} }); var B = Class.create(A, function(){ function nifty(){ nifty.$super.call(this); } return {nifty: nifty}; }); How about simplifying further: var B = Class.create( A, function nifty(){ nifty.$super.call(this); } , function alsoNifty(){ this.nifty(); } ); Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
@TJ I don't think it would be hard to tell the difference between a base class construct and a function. You would just need some extra work in construction of the base class. After the construction of klass, you could set a property so that it is identifiable. For example: function klass() { this.initialize.apply(this, arguments); } if( !klass.name ) klass.name = 'klass'; Then you could do: if(Object.isFunction(value)){ if(value.name === 'klass'){ //Do base class stuff } else { //Do function generator } } I hope its clear where these snippets relate to the source. Allen Madsen http://www.allenmadsen.com On Tue, Sep 8, 2009 at 11:18 AM, T.J. Crowder t...@crowdersoftware.com wrote: @Allen, For your two suggested additions. I don't think I have ever had a use for either. Thanks. One thing I would like to suggest though is that Class.create take an object or a function as an argument. I _really_ like that idea, not least because it seems to me that by reducing the *seeming* complexity it makes it much easier for relative novices to adopt using named functions. But unfortunately it would a further API change, because otherwise Class.create can't tell whether the first argument is a base class constructor or a function you want it to call to retrieve the members object: var X = Class.create(BaseClass); var Y = Class.create(function() { function nifty() { ... } return {nifty: nifty}; }); You see the problem. The API change wouldn't need to be large, it's just suddenly we're impacting the API more than we otherwise have to, and my gut reaction to that is usually caution (not least because unless I caution myself, I get a bit change-happy). None of which is meant to say A) That I'd be opposed to it if a bunch of smart people said it was worth it (quite the opposite, in fact); or B) That I'm not going to *immediately* steal your idea for my own projects. :-) FWIW, and there are 18 ways to skin this cat, but if we did anything I'd prefer to leave Class.create alone, but I'd be really interested in the idea of providing a new entry point (Class.define, perhaps) that provides this new functionality and which solves the problem of how to specify the base class in some clever way. Perhaps a new thread for this sub-topic? @Jim, Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. -- T.J. :-) On Sep 8, 3:27 pm, Allen Madsen bla...@gmail.com wrote: Jim, I like your suggestion, except that there would be no way to create private variables and functions that could be used in more than one function. For example, with my suggested method I could do: Var A = Class.create(function(){ var privateVar = 0; function privateFunction(){} function nifty(){ privateFunction(); privateVar = 3; } return {nifty: nifty}; }); I'd much rather see it in this form. Allen Madsenhttp://www.allenmadsen.com On Tue, Sep 8, 2009 at 10:12 AM, Jim Higson j...@wikizzle.org wrote: On Tuesday 08 September 2009 14:56:06 Allen Madsen wrote: Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding callee), it would be nice if defining that was simplified. So something like: var A = Class.create({ nifty: function(){} }); var B = Class.create(A, function(){ function nifty(){ nifty.$super.call(this); } return {nifty: nifty}; }); How about simplifying further: var B = Class.create( A, function nifty(){ nifty.$super.call(this); } , function alsoNifty(){ this.nifty(); } ); Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Allen, After the construction of klass, you could set a property so that it is identifiable. Doh! Of course, since we only allow deriving from classes created via Class.create. I wouldn't go with name, though, since the ECMAScript5 spec actually defines name for functions. But _createdByPrototype would work (and echos the _extendedByPrototype property on extended Elements)... Gets my vote, as you say, makes the syntax much more like several other things we do: var Thingy = Class.create(function(){ // Define function nifty() { ... } function spiffy() { ... } function keen() { ... } // Export public methods return {nifty: nifty, spiffy: spiffy, keen: keen}; }); ...while still accepting the form where we've already been given an object. Nice one! -- T.J. Crowder tj / crowder software / com www.crowdersoftware.com On Sep 8, 5:00 pm, Allen Madsen bla...@gmail.com wrote: @TJ I don't think it would be hard to tell the difference between a base class construct and a function. You would just need some extra work in construction of the base class. After the construction of klass, you could set a property so that it is identifiable. For example: function klass() { this.initialize.apply(this, arguments);} if( !klass.name ) klass.name = 'klass'; Then you could do: if(Object.isFunction(value)){ if(value.name === 'klass'){ //Do base class stuff } else { //Do function generator } } I hope its clear where these snippets relate to the source. Allen Madsenhttp://www.allenmadsen.com On Tue, Sep 8, 2009 at 11:18 AM, T.J. Crowder t...@crowdersoftware.com wrote: @Allen, For your two suggested additions. I don't think I have ever had a use for either. Thanks. One thing I would like to suggest though is that Class.create take an object or a function as an argument. I _really_ like that idea, not least because it seems to me that by reducing the *seeming* complexity it makes it much easier for relative novices to adopt using named functions. But unfortunately it would a further API change, because otherwise Class.create can't tell whether the first argument is a base class constructor or a function you want it to call to retrieve the members object: var X = Class.create(BaseClass); var Y = Class.create(function() { function nifty() { ... } return {nifty: nifty}; }); You see the problem. The API change wouldn't need to be large, it's just suddenly we're impacting the API more than we otherwise have to, and my gut reaction to that is usually caution (not least because unless I caution myself, I get a bit change-happy). None of which is meant to say A) That I'd be opposed to it if a bunch of smart people said it was worth it (quite the opposite, in fact); or B) That I'm not going to *immediately* steal your idea for my own projects. :-) FWIW, and there are 18 ways to skin this cat, but if we did anything I'd prefer to leave Class.create alone, but I'd be really interested in the idea of providing a new entry point (Class.define, perhaps) that provides this new functionality and which solves the problem of how to specify the base class in some clever way. Perhaps a new thread for this sub-topic? @Jim, Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. I see where you're coming from, but FWIW I'm with Allen on this one. Also, there's no standard way to get the name of a function until ECMAScript5 (which standardizes the truly outrageous idea that function instances should have -- gasp! -- a name property), and at the moment although Firefox 3.5, Chrome 2, and Safari 4 all already have that property, IE7 (at least, haven't tested IE8) and Opera10 do not. -- T.J. :-) On Sep 8, 3:27 pm, Allen Madsen bla...@gmail.com wrote: Jim, I like your suggestion, except that there would be no way to create private variables and functions that could be used in more than one function. For example, with my suggested method I could do: Var A = Class.create(function(){ var privateVar = 0; function privateFunction(){} function nifty(){ privateFunction(); privateVar = 3; } return {nifty: nifty}; }); I'd much rather see it in this form. Allen Madsenhttp://www.allenmadsen.com On Tue, Sep 8, 2009 at 10:12 AM, Jim Higson j...@wikizzle.org wrote: On Tuesday 08 September 2009 14:56:06 Allen Madsen wrote: Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Robert, Thanks for your thoughts on this. The requirement for named function expressions (NFEs) puts a serious crimp in developers coding style. This mechanism does _not_ require NFEs. You can use anonymous functions and call the super via arguments.callee if you like, and still get big performance improvement (and stop relying on function decompilation, although you lose ECMA5 strict mode compliance). The invocation syntax if you use anonymous functions is ugly enough: var Thingy = Class.create({ nifty: function(arg) { arguments.callee.$super.call(this, arg); } }); ...that I would (in fact, did) suggest a helper: var Thingy = Class.create({ nifty: function(arg) { this.callSuper(arguments, arg); } }); Before I dive into details, though, can someone please tell me why we're not looking at Dean Edwards old Base2 approach[1], or John Resig's variation on that[2]? We should definitely consider various options. This started because I sort of accidentally went down a road, found what I thought was a really nifty solution, and posted asking whether others were interested in it. My issue with Resig's approach would be the number of introduced closures and the slippery _super method, which has too much magic in it for my taste. These things are subjective. It also won't perform as well, but we're talking a small increment, and as you say trade- offs come into play. I mean, come on, close your eyes, take a few deep breaths, and then look at it... nifty.$super.call(this, spiffy) There are lots of constructs that look a bit alien at first. To me this isn't one of them (and I'm no JavaScript master) but I totally recognise that for some novices there's going to be a certain amount of just do it like this, eventually you'll understand why. That's true of lots of things. A novice who doesn't know about Function#call needs to be taught about Function#call, in my view. If we provide a helper, it could accept either 'arguments' (for anonymous functions) or the function instance (for named fucntions), so this: nifty.$super.call(this, spiffy); ...could be: this.callSuper(nifty, spiffy); ...if we think that's more helpful. The cost is an extra function call, which compared with the various other savings we're making isn't a big deal. Thanks again for jumping into this, -- T.J. Crowder tj / crowder software / com www.crowdersoftware.com On Sep 8, 4:11 pm, Robert Kieffer bro...@gmail.com wrote: I still have some serious reservations about this patch. Before I dive into details, though, can someone please tell me why we're not looking at Dean Edwards old Base2 approach[1], or John Resig's variation on that[2]? That general approach would seem to offer a good trade-off between performance and usability. ... and it's that trade-off I have reservations about. If Prototype is going to replace the current $super technique, it's this tradeoff that I would like to see a nice balance on. And with all respect to you, T.J., I don't think your solution has that. There's no question it is more performant (woot!), but I have serious doubts about it's overall usability. The requirement for named function expressions (NFEs) puts a serious crimp in developers coding style. Having to declare the functions in one section and then wrap them up in a returned data structure in another... It's nice that this style works for Prototype, and I appreciate the advantages, but it's not exactly commonplace (not that anything is). It'll definitely give more than one developer pause. Can I politely suggest that maybe you guys are a bit too close to the code and are taking the learning curve here for granted? And having to explicitly type the name of each function 3-4 times to define it will very quickly get tiresome. It makes writing code harder, and it makes refactoring it harder as well. Which means more prone to error; there is still no IDE that is able to automatically and accurately change the name of functions when declared like this. With all the drum-beating around here about code maintainability, I'm a little surprised to see this issue treated so lightly. Most importantly, the syntax for invoking a supermethod, while not quite as horrid as some others we've seen and discussed, is still not that great. I mean, come on, close your eyes, take a few deep breaths, and then look at it... nifty.$super.call(this, spiffy) ... .vs. the current style: $super(spiffy) ... or what the Dean Edwards/John Resig style: this._super(spiffy) I know, I know, the current style has performance issues. But for a lot of developers a simpler, less confusing syntax will trump that. I suspect most will continue to use the old $super scheme, which will make it much harder to deprecate than you might expect. And if the old $super scheme is gonna stick around for a while because
[Prototype-core] Re: A more efficient $super for Prototype 2
Jim, I like your suggestion, except that there would be no way to create private variables and functions that could be used in more than one function. For example, with my suggested method I could do: Var A = Class.create(function(){ var privateVar = 0; function privateFunction(){} function nifty(){ privateFunction(); privateVar = 3; } return {nifty: nifty}; }); I'd much rather see it in this form. Allen Madsen http://www.allenmadsen.com On Tue, Sep 8, 2009 at 10:12 AM, Jim Higson j...@wikizzle.org wrote: On Tuesday 08 September 2009 14:56:06 Allen Madsen wrote: Hey TJ, For your two suggested additions. I don't think I have ever had a use for either. One thing I would like to suggest though is that Class.create take an object or a function as an argument. Since it is essentially a requirement now to use a function to create named functions that can call super (disregarding callee), it would be nice if defining that was simplified. So something like: var A = Class.create({ nifty: function(){} }); var B = Class.create(A, function(){ function nifty(){ nifty.$super.call(this); } return {nifty: nifty}; }); How about simplifying further: var B = Class.create( A, function nifty(){ nifty.$super.call(this); } , function alsoNifty(){ this.nifty(); } ); Ie, Class.create takes any number of objects of functions or functions. If functions, the function name is used. -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Sep 8, 8:44 am, T.J. Crowder t...@crowdersoftware.com wrote: arguments.callee.$super.call(this, arg); this.callSuper(arguments, arg); six of one, half-dozen of the other... but I suppose there is no perfect solution. Still, it's hard to swallow something this convoluted when you've gotten used to $super (or this._super() ) :-P My issue with Resig's approach would be the number of introduced closures and the slippery _super method, which has too much magic in it for my taste. These things are subjective. It also won't perform as well, but we're talking a small increment, and as you say trade- offs come into play. I have to confess it's been long enough since I looked at that code that I don't have an opinion about it. I do know that it performance tested well, and I definitely prefer the invocation syntax. Honestly, at this point I'm mostly worried that that we may get enamored with a solution that is different, but not necessarily all that much better. More performant, yes, but at the cost of usability. I'm tempted, even, to argue for the removal of supermethod invocation altogether in Prototype. It's not like it actually needs it - there are a couple places where $super is used, but it would be trivial to rewrite that to where it's not necessary. Developers would benefit from a smaller Prototype codebase, and they code pick and choose the supermethod technique that best met their needs, and import the appropriate script for that. That notion is both heretical and ironic I suppose, since I guess I started the whole look how shitty Prototype supermethod performance is! thread. But history has taught me that developers who write code without having a concrete use for it very rarely make the right choices. It's much better to let requirements drive the code choices, rather than the other way around. Okay, climbing down off my soapbox now to go get lunch. :-) - rwk --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Robert, arguments.callee.$super.call(this, arg); this.callSuper(arguments, arg); six of one, half-dozen of the other... Um, this.callSuper(arguments, arg) (or this.callSuper(nifty, arg)) is precisely *one* argument more than Resig's this._super(arg), but without the cost of the closures and unnecessary, misleading (IMV) magic. It's a lot clearer than the raw syntax needed with anonymous functions. Six of one, half-dozen of the other seems a bit harsh. Honestly, at this point I'm mostly worried that that we may get enamored with a solution that is different, but not necessarily all that much better. More performant, yes, but at the cost of usability... That's interesting. I started down this road precisely because I found the existing API flawed; the performance and compliance aspects came later. I'm not at all interested in replacing things without a compelling reason, we all have better things to do. I'm tempted, even, to argue for the removal of supermethod invocation altogether in Prototype. FWIW, I think that would be a mistake (but then, I use supercalls and had a concrete reason for going down this path). Not only because it's a useful feature, but also because it's one of the things people of a certain background look for in a JavaScript library. I didn't realize you'd done a crappy performance in supercalls thrread (I was away from this group for a while). I'd seen the excellent work you did with curried and bound functions, though, and I'm glad to hear that will be finding its way into 1.6.1. -- T.J. :-) On Sep 8, 7:43 pm, Robert Kieffer bro...@gmail.com wrote: On Sep 8, 8:44 am, T.J. Crowder t...@crowdersoftware.com wrote: arguments.callee.$super.call(this, arg); this.callSuper(arguments, arg); six of one, half-dozen of the other... but I suppose there is no perfect solution. Still, it's hard to swallow something this convoluted when you've gotten used to $super (or this._super() ) :-P My issue with Resig's approach would be the number of introduced closures and the slippery _super method, which has too much magic in it for my taste. These things are subjective. It also won't perform as well, but we're talking a small increment, and as you say trade- offs come into play. I have to confess it's been long enough since I looked at that code that I don't have an opinion about it. I do know that it performance tested well, and I definitely prefer the invocation syntax. Honestly, at this point I'm mostly worried that that we may get enamored with a solution that is different, but not necessarily all that much better. More performant, yes, but at the cost of usability. I'm tempted, even, to argue for the removal of supermethod invocation altogether in Prototype. It's not like it actually needs it - there are a couple places where $super is used, but it would be trivial to rewrite that to where it's not necessary. Developers would benefit from a smaller Prototype codebase, and they code pick and choose the supermethod technique that best met their needs, and import the appropriate script for that. That notion is both heretical and ironic I suppose, since I guess I started the whole look how shitty Prototype supermethod performance is! thread. But history has taught me that developers who write code without having a concrete use for it very rarely make the right choices. It's much better to let requirements drive the code choices, rather than the other way around. Okay, climbing down off my soapbox now to go get lunch. :-) - rwk --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Allen, You can do this already pretty easily. Just do: Var A = Class.create(function(){ var privateVar = 0; function privateFunction(){} function nifty(){ privateFunction(); privateVar = 3; } return {nifty: nifty}; }()); Just note that in both cases, those private variables are `class` variables shared between all instances. --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Sep 8, 11:11 am, Robert Kieffer bro...@gmail.com wrote: I still have some serious reservations about this patch. Before I dive into details, though, can someone please tell me why we're not looking at Dean Edwards old Base2 approach[1], or John Resig's variation on that[2]? That general approach would seem to offer a good trade-off between performance and usability. Last time I checked, Resig's implementation relied on function decompilation too, which we are trying to avoid this time. ... and it's that trade-off I have reservations about. If Prototype is going to replace the current $super technique, it's this tradeoff that I would like to see a nice balance on. And with all respect to you, T.J., I don't think your solution has that. There's no question it is more performant (woot!), but I have serious doubts about it's overall usability. The requirement for named function expressions (NFEs) puts a serious crimp in developers coding style. Having to declare the functions in Actually, there's no such requirement. You are free to use anonymous function expressions, named function expressions or function declarations. You only need to have a reference to a function; doesn't matter how you created it and which identifier you gave to it. var f; Class.create({ initialize: (f = function(){ // ... }) }); There's your `f`, referencing function in question. No Identifier needed. one section and then wrap them up in a returned data structure in another... It's nice that this style works for Prototype, and I appreciate the advantages, but it's not exactly commonplace (not that anything is). It'll definitely give more than one developer pause. Can I politely suggest that maybe you guys are a bit too close to the code and are taking the learning curve here for granted? And having to explicitly type the name of each function 3-4 times to define it will very quickly get tiresome. It makes writing code harder, and it makes refactoring it harder as well. Which means more I agree. Repetition of function names is by far the biggest downside to this approach. And, of course, it is impossible to not repeat function name without either relying on function decompilation or completely hog performance by blindly wrapping every single method with a closure to its parent. [...] -- kangax --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
T.J., could you point me to the exact section specifying `name` on Function objects? I don't remember seeing it in ES5. That's because it's not part of that spec. If I remember correctly it was discussed for Harmony. Best, Tobie --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Tue, Sep 8, 2009 at 1:21 PM, T.J. Crowder t...@crowdersoftware.com wrote: Hi Robert, arguments.callee.$super.call(this, arg); this.callSuper(arguments, arg); six of one, half-dozen of the other... Um, this.callSuper(arguments, arg) (or this.callSuper(nifty, arg)) is precisely *one* argument more than Resig's this._super(arg), but without the cost of the closures and unnecessary, misleading (IMV) magic. It's a lot clearer than the raw syntax needed with anonymous functions. Six of one, half-dozen of the other seems a bit harsh. I apologize, I was being glib (hence the quotes.) But there is a grain of truth there. Both these incantations are unintuitive in their own way. callSuper may have only one more argument but it's a wierd one for sure. Especially for developers unfamiliar with 'arguments' and its 'callee' property. Many devs will treat this as yet another piece of JS voodoo code they have to remember - you do it just because. And what if the super method takes different arguments than the sub method, Wait a minute, why am I passing an array with 'foo' 'bar' in it, when I only want to hand 'baz' to the supermethod? Honestly, at this point I'm mostly worried that that we may get enamored with a solution that is different, but not necessarily all that much better. More performant, yes, but at the cost of usability... That's interesting. I started down this road precisely because I found the existing API flawed; Was it the API you found flawed, or the implementation of that API? I think the $super argument is a rather elegant solution. Non-standard, sure, and lacking performance, but conceptually elegant. In essence: If you need to access $super, just pass it to yourself as the first argument. It's easy to remember, and hard to screw up. I didn't realize you'd done a crappy performance in supercalls thrread (I was away from this group for a while). I'd seen the excellent work you did with curried and bound functions, though, and I'm glad to hear that will be finding its way into 1.6.1. It wasn't a thread in this group but, rather, the blog post I did a while back that got some attention on Ajaxian.com and that other folks ran with for a bit on their own blogs: http://ajaxian.com/archives/javascript-inheritance-performance --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
TJ... I once woke up from a nap in the middle of a saturday and solved a silly issue i was having with event bubbling/propagation... I had seen the solution in code as the last thing before I woke up. I tried it... and it worked. The point: never feel bad about waking up to code on the brain :) Rick On Sun, Sep 6, 2009 at 5:38 AM, T.J. Crowder t...@crowdersoftware.com wrote: I think you need this.nifty.$super.call(this, foo); You don't, although that also works. Ack! Sorry, too early in the morning, hadn't had enough coffee. That does *not* work, because you always refer to the bottommost subclass's nifty (this.nifty is always the bottommost function), so you end up endlessly recursing. Wow that's an easy trap to fall into. No, it's either use the function's name unadorned, or use arguments.callee and pay the performance penalty. Personally, I prefer using the function's name. :-) -- T.J. :-) On Sep 6, 8:48 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi Allen, I think you need this.nifty.$super.call(this, foo); You don't, although that also works. A named function's name is in scope within the function: function foo(bar) { alert(typeof foo); // Alerts function } However, I was thinking about anonymous functions this morning while waking up (pathetic, isn't it?) and realized that even if you don't use a named function, you can avoid arguments.callee with exactly the form you describe: this.nifty.$super.call(this, foo); I don't like the repetition of this, but if you don't have time to switch everything over to named functions (I'm thinking of retrofitting efforts), it's a reasonable first step, and I assume (haven't tested it yet) still gets speed gains over arguments.callee. Will be posting a sample implementation (it's wonderfully simple, but there are a couple of edge cases around dynamic updates of classes) and tests ASAP, but I want to get some of the Prototype documentation issues sorted out first (transferring the old doc to the new format and updating), since that's more urgent. -- T.J. :-) On Sep 5, 2:46 pm, Allen Madsen bla...@gmail.com wrote: var Thingy = Class.create({ nifty: function nifty(foo, bar) { nifty.$super.call(this, foo); } }); It just ignores the function name and complains that 'nifty' is not defined. This works: I think you need this.nifty.$super.call(this, foo); Allen Madsenhttp://www.allenmadsen.com --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
TJ, I guess I don't understand why it wouldn't work. I'll illustrate how I understand it and you correct me where I'm wrong. var A = Class.create({ nifty: function(){} }); var B = Class.create(A, { nifty: function(){ this.nifty.$super(); // refers to A.nifty() //this.nifty(); //would cause recursion } }); Also, if what I'm thinking is correct, there are some interesting side effects that weren't possible before. Such as: var C = Class.create(B, { nifty: function(){ this.nifty.$super.$super(); //refers to A.nifty() instead of B.nifty() }, crappy: function(){ this.nifty.$super(); //calls super of another function } }); Allen Madsen http://www.allenmadsen.com On Sun, Sep 6, 2009 at 5:38 AM, T.J. Crowder t...@crowdersoftware.com wrote: I think you need this.nifty.$super.call(this, foo); You don't, although that also works. Ack! Sorry, too early in the morning, hadn't had enough coffee. That does *not* work, because you always refer to the bottommost subclass's nifty (this.nifty is always the bottommost function), so you end up endlessly recursing. Wow that's an easy trap to fall into. No, it's either use the function's name unadorned, or use arguments.callee and pay the performance penalty. Personally, I prefer using the function's name. :-) -- T.J. :-) On Sep 6, 8:48 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi Allen, I think you need this.nifty.$super.call(this, foo); You don't, although that also works. A named function's name is in scope within the function: function foo(bar) { alert(typeof foo); // Alerts function } However, I was thinking about anonymous functions this morning while waking up (pathetic, isn't it?) and realized that even if you don't use a named function, you can avoid arguments.callee with exactly the form you describe: this.nifty.$super.call(this, foo); I don't like the repetition of this, but if you don't have time to switch everything over to named functions (I'm thinking of retrofitting efforts), it's a reasonable first step, and I assume (haven't tested it yet) still gets speed gains over arguments.callee. Will be posting a sample implementation (it's wonderfully simple, but there are a couple of edge cases around dynamic updates of classes) and tests ASAP, but I want to get some of the Prototype documentation issues sorted out first (transferring the old doc to the new format and updating), since that's more urgent. -- T.J. :-) On Sep 5, 2:46 pm, Allen Madsen bla...@gmail.com wrote: var Thingy = Class.create({ nifty: function nifty(foo, bar) { nifty.$super.call(this, foo); } }); It just ignores the function name and complains that 'nifty' is not defined. This works: I think you need this.nifty.$super.call(this, foo); Allen Madsenhttp://www.allenmadsen.com --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
I think you need this.nifty.$super.call(this, foo); You don't, although that also works. Ack! Sorry, too early in the morning, hadn't had enough coffee. That does *not* work, because you always refer to the bottommost subclass's nifty (this.nifty is always the bottommost function), so you end up endlessly recursing. Wow that's an easy trap to fall into. No, it's either use the function's name unadorned, or use arguments.callee and pay the performance penalty. Personally, I prefer using the function's name. :-) -- T.J. :-) On Sep 6, 8:48 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi Allen, I think you need this.nifty.$super.call(this, foo); You don't, although that also works. A named function's name is in scope within the function: function foo(bar) { alert(typeof foo); // Alerts function } However, I was thinking about anonymous functions this morning while waking up (pathetic, isn't it?) and realized that even if you don't use a named function, you can avoid arguments.callee with exactly the form you describe: this.nifty.$super.call(this, foo); I don't like the repetition of this, but if you don't have time to switch everything over to named functions (I'm thinking of retrofitting efforts), it's a reasonable first step, and I assume (haven't tested it yet) still gets speed gains over arguments.callee. Will be posting a sample implementation (it's wonderfully simple, but there are a couple of edge cases around dynamic updates of classes) and tests ASAP, but I want to get some of the Prototype documentation issues sorted out first (transferring the old doc to the new format and updating), since that's more urgent. -- T.J. :-) On Sep 5, 2:46 pm, Allen Madsen bla...@gmail.com wrote: var Thingy = Class.create({ nifty: function nifty(foo, bar) { nifty.$super.call(this, foo); } }); It just ignores the function name and complains that 'nifty' is not defined. This works: I think you need this.nifty.$super.call(this, foo); Allen Madsenhttp://www.allenmadsen.com --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hey gang, I took a look at this issue a while ago, in a blog post that generated a fair bit of discussion and spin off investigations (see http://www.google.com/search?q=inheritance+performance+javascript) so I'll try to weigh in. However I'm in the middle of an extended road trip, so I don't have the time/resources necessary to give this proper attention... http://ejohn.org/blog/simple-javascript-inheritance - JQ's swipe at this problem. Definitely read through the comments. Your approach appears similar to his (which is based on Dean Edward's Base2). Dean uses this.base(), instead of this.callSuper(), fwiw. no strong opinions there, although this.base() seems a bit more prototype-like in it's terseness. The performance tests I did for Base2 (see the broofa.com article in the google search above) are probably a good first-guess at the performance your approach will have compared to other techniques. Technically this doesn't break backward compatibility - $super and this.callSuper() can coexist as dual techniques for doing inheritance, correct? We just need to decide if $super support will continue in P2. ... and, finally, I vaguely recall people raising some interesting edge cases. But I don't remember where I saw those. *sigh*. - rwk --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Friday 04 September 2009 14:09:32 T.J. Crowder wrote: [...] I do _not_ mean that I think callSuper is a great name; I don't and I expect suggestions like yours to result in a better name. But something unlikely to clash makes it simpler for people to do a global search-and-replace to convert $super(...) to this.niftyNameHere(arguments, ...). How about this.$super()? -- Jim my wiki ajaxification thing: http://wikizzle.org my blog: http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
@Allen @Jim, Gets my vote. -- T.J. :-) On Sep 4, 3:05 pm, Jim Higson j...@wikizzle.org wrote: On Friday 04 September 2009 14:09:32 T.J. Crowder wrote: [...] I do _not_ mean that I think callSuper is a great name; I don't and I expect suggestions like yours to result in a better name. But something unlikely to clash makes it simpler for people to do a global search-and-replace to convert $super(...) to this.niftyNameHere(arguments, ...). How about this.$super()? -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi again folks, This thread[1] about using Array.prototype.slice to copy arguments made me wonder whether the speed improvements I found had more to do with the fact my implementation of the new mechanism had its own copy- the-args function (which is faster than using `slice` on most browsers; see the thread for details) than with eliminating calls and function creation. And the answer is: No, but with the important caveat: On Chrome when using the callSuper helper, a big part of the gains were indeed down to the copy-the-args function instead of `slice`. If I modify my new mechanism to use `slice` instead (which obviously is the wrong way 'round, but never mind), when using the helper the new mechanism is only about 2X faster on Chrome than the old mechanism. Of course, Firefox got faster in that scenario (since Firefox is the one browser in my set of tests where using `slice` is faster than one's own copy function). So summing up, the new mechanism remains faster across-the-board even using the helper, but the gains on Chrome will not be as marked (when using a helper) as they seem at present because of the difference in how args are copied. And of course, one of the great things about the new mechanism is that you don't have to copy args at all if you are willing to use the more verbose syntax. [1] http://groups.google.com/group/prototype-core/browse_thread/thread/cf8c287e231a0192# -- T.J. Crowder tj / crowder software / com www.crowdersoftware.com On Sep 4, 3:09 pm, T.J. Crowder t...@crowdersoftware.com wrote: @Allen @Jim, Gets my vote. -- T.J. :-) On Sep 4, 3:05 pm, Jim Higson j...@wikizzle.org wrote: On Friday 04 September 2009 14:09:32 T.J. Crowder wrote: [...] I do _not_ mean that I think callSuper is a great name; I don't and I expect suggestions like yours to result in a better name. But something unlikely to clash makes it simpler for people to do a global search-and-replace to convert $super(...) to this.niftyNameHere(arguments, ...). How about this.$super()? -- Jim my wiki ajaxification thing:http://wikizzle.org my blog:http://jimhigson.blogspot.com/ --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Prototype: Core group. To post to this group, send email to prototype-core@googlegroups.com To unsubscribe from this group, send email to prototype-core-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en -~--~~~~--~~--~--~---
[Prototype-core] Re: A more efficient $super for Prototype 2
On Sep 4, 8:15 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi all, I've come up with a new way of handling $super (which I can't imagine is unique, it's just new to me) which is markedly more efficient than our current $super on all of the browsers I've tried it on. I'm wondering whether we should consider it for Prototype 2. Our current solution is clearly one of the slowest inheritance implementations out there. You get very nice sugar for a very high price :) No surprises there. I think P2 should definitely employ a simpler approach (either fully replacing old one or just as a separate option). It's worth mentioning that one of the warts of current solution is that it relies on function decompilation - something that's known to cause problems [1][2] and is better avoided (fwiw, ES committee didn't have enough time to handle this issue so ES5 specifies `Function.prototype.toString` to return the very same *implementation- dependent* function representation) Executive summary: Pros - * Avoids calling toString on subclass methods when defining classes. * Avoids creating closures for each $super-enabled subclass method. * Avoids creating an on-the-fly function on every call to a $super- enabled method. * Avoids at least four extra calls when $super-enabled methods are called. * Consequently reduces the time to call methods that use $super, from markedly (1.6X as fast) to dramatically (10X as fast) depending on browser and choices the subclass author makes. * Theoretically reduces memory footprint (no added functions/ closures). * Minifiers (like packer3) that change arg names don't break things by renaming $super. * (Subjective) Simpler code in Class.create for contribs to understand. Cons - * Breaks backward compatibility. * Syntax for calling the $super method is slightly more complex. * Relies on `arguments.callee` with all the consequences. To explain consequences: `arguments.callee` is considered one of the warts of ES3. Besides certain security concerns, the bad part of it is that it requires creation of `arguments` object (when entering execution context). This creation is rather expensive and results in both - memory and perf. hits. Some of the modern implementations optimize in such way that they only create `arguments` object when it statically occurs in a function body (or when there's a chance of dynamic evaluation, such as `eval`, `setTimeout` occurrence, etc.). Others create `arguments` object on first resolution of `arguments` identifier, etc. You can easily see it by yourself. Create 2 identical functions, one of which would use `arguments.callee` and another - plain identifier; then look at a difference. ES5 also introduces strict mode. When in strict mode, `argument.callee` throws TypeError on access. IIRC, Caja (secure subset of ES) and some of its variations (Cajita, Valija), emulate ES5- strict behavior and also throw error. If something in Prototype were to rely on `arguments.callee`, it would effectively prevent running it in strict mode or cajoling it. [snip current approach explanation] Here's how the new approach works: 1. At class definition time, Class.create detects that the subclass overrides the superclass's method (this is a trivial property check) and, if so, stores a reference to the super's function as a property called $super on the sub's function object. 2. When a method is called, there is no indirection, the call goes direct to the subclass's defined method. The subclass can then call the super's version via arguments.callee.$super. The unaided syntax subclass methods would use to call the super's version is complicated and error-prone (to the novice, anyway): nifty: function(foo, bar) { arguments.callee.$super.call(this, foo); } ...and so this solution envisions a helper callSuper method (name TBD) authors may choose to use instead (at the cost of an extra function call): nifty: function(foo, bar) { this.callSuper(arguments, foo); } You can see why I think a helper may be useful; that's quite a lot simpler. Note that the first argument is always 'arguments' and does *not* mean #callSuper is passing all of the arguments to the super function; you follow it with the arguments you want to pass. We can muck about with the API on the helper, and of course class authors can create their own for their own needs. I usually use a similar approach instead of `$super`, which I first saw mentioned by Tobie some time ago: Class.Methods.callSuper = function(methodName) { var fn = this.constructor.superclass.prototype[methodName]; return (arguments.length 1) ? fn.apply(this, _slice.call(arguments, 1)) : fn.call(this); } then: initialize: function(options) { ... this.callSuper('initialize', options); ... } One huge downside to this is that there's now repetition of method name. If I change method name, I also have to remember to change first
[Prototype-core] Re: A more efficient $super for Prototype 2
Hi Juriy, Thanks for that. Yes, it was the function decompilation (and the on- the-fly bind) that made me look for another solution. I was unaware of the performance implication of arguments.callee, and *WOW* does it make a speed difference (see below). The good thing is that this solution doesn't require arguments.callee (we'll have to adjust the helper, or do away with it). Just name your functions and use the name. You _can_ use arguments.callee if you like, but for best results, use function names. Because **HOLY COW** what a difference that makes. Using the function's name instead makes the new mechanisn 16-50X faster (I kid you not) than the old on Chrome. Firefox also goes through the roof speed-wise, we're talking 35X+. Even IE is more impressed, going from 1.6X to 2.4X as fast. Opera says yes, please with a 11X improvement, as does Safari with 10X. The fly in the ointment is that IE will not acknowledge the function name if defined as part of an assignment/initialization statement like so: var Thingy = Class.create({ nifty: function nifty(foo, bar) { nifty.$super.call(this, foo); } }); It just ignores the function name and complains that 'nifty' is not defined. This works: var Thingy = Class.create((function() { function nifty(foo, bar) { nifty.$super.call(this, foo); } return {nifty: nifty}; })()); (Which is what a lot of the Prototype source now does.) So that's a larger impact on how you define classes, but also suggests a useful pattern to authors for sharing common private class methods/data within the closure, and WOW what a performance difference. There seems to be enough interest in this that it's worth my doing a sample changeset with test cases and sharing it 'round; I'll do that over the weekend. -- T.J. Crowder tj / crowder software / com www.crowdersoftware.com On Sep 4, 6:25 pm, kangax kan...@gmail.com wrote: On Sep 4, 8:15 am, T.J. Crowder t...@crowdersoftware.com wrote: Hi all, I've come up with a new way of handling $super (which I can't imagine is unique, it's just new to me) which is markedly more efficient than our current $super on all of the browsers I've tried it on. I'm wondering whether we should consider it for Prototype 2. Our current solution is clearly one of the slowest inheritance implementations out there. You get very nice sugar for a very high price :) No surprises there. I think P2 should definitely employ a simpler approach (either fully replacing old one or just as a separate option). It's worth mentioning that one of the warts of current solution is that it relies on function decompilation - something that's known to cause problems [1][2] and is better avoided (fwiw, ES committee didn't have enough time to handle this issue so ES5 specifies `Function.prototype.toString` to return the very same *implementation- dependent* function representation) Executive summary: Pros - * Avoids calling toString on subclass methods when defining classes. * Avoids creating closures for each $super-enabled subclass method. * Avoids creating an on-the-fly function on every call to a $super- enabled method. * Avoids at least four extra calls when $super-enabled methods are called. * Consequently reduces the time to call methods that use $super, from markedly (1.6X as fast) to dramatically (10X as fast) depending on browser and choices the subclass author makes. * Theoretically reduces memory footprint (no added functions/ closures). * Minifiers (like packer3) that change arg names don't break things by renaming $super. * (Subjective) Simpler code in Class.create for contribs to understand. Cons - * Breaks backward compatibility. * Syntax for calling the $super method is slightly more complex. * Relies on `arguments.callee` with all the consequences. To explain consequences: `arguments.callee` is considered one of the warts of ES3. Besides certain security concerns, the bad part of it is that it requires creation of `arguments` object (when entering execution context). This creation is rather expensive and results in both - memory and perf. hits. Some of the modern implementations optimize in such way that they only create `arguments` object when it statically occurs in a function body (or when there's a chance of dynamic evaluation, such as `eval`, `setTimeout` occurrence, etc.). Others create `arguments` object on first resolution of `arguments` identifier, etc. You can easily see it by yourself. Create 2 identical functions, one of which would use `arguments.callee` and another - plain identifier; then look at a difference. ES5 also introduces strict mode. When in strict mode, `argument.callee` throws TypeError on access. IIRC, Caja (secure subset of ES) and some of its variations (Cajita, Valija), emulate ES5- strict behavior and also throw error. If something in Prototype