Russell Leggett (2013-10-21T19:35:46.000Z)
domenic at domenicdenicola.com (2013-10-28T19:55:57.308Z)
On Mon, Oct 21, 2013 at 3:17 PM, Benjamin (Inglor) Gruenbaum <inglor at gmail.com> wrote: > what's "the default" in #4? The protocol's default? What's the behavior if > no matching method is found? The default is something I go into in a little bit of detail further down: Collections.defaults({ each(iterator, context){ if (this.length === +this.length) { for (var i = 0, length = this.length; i < length; i++) { //notice we also get to use :: for a simple call replacement if (context::iterator(this[i], i, this) === breaker) return; } } else { var keys = this.keys(); for (var i = 0, length = keys.length; i < length; i++) { if (context::iterator(this[keys[i]], this[i], this) === breaker) return; } } }, This is defining a sort of default implementation of the method for the protocol, meaning that other types do not have to implement it in their own type specific implementation of the protocol. > Also, can anyone explain why this solves the performance problem scoped > object extensions have? It still seems like it would have to check the > environment for protocols and then check the methods on all available > protocols and do type matching to the type of the method. > > `Collections.extend(Array)` seems awfully similar to an array extensions, > how does the `::` operator resolve the need for expensive lookup, can you > explain that to me? > Yes, the reason is because no new scopes or environments have been created. The protocol and its methods are simply variables - objects like anything else. Getting a protocol's method is not really any different from: ```js import {map} from 'UnderscOOre'; //basically the same as let {map} = Array.prototype; //this is effectively the same whether you got it from the protocol or the function //pulled off of Array.prototype arr::map( x => x+2); ``` The magic is what happens one of these protocol methods. The simplest to understand/naive approach to this would basically be that inside of a protocol, for each protocol method, you hold all the methods in a map going from type to implementation. The actual method used would inspect the |this| and follow the algorithm and use the maps to figure out which implementation to use. This would have a penalty - but it would be limited to the protocol method calls. Scoped extension would apply a penalty to *all* function calls everywhere. If protocols were natively supported, or at least some kind of hook for single dispatch on type, I'm pretty sure you could get function calls that were *at least* as fast as normal prototype based methods. Even if you didn't get native support, I have a feeling that something more clever than the naive approach could be used to hit the sweet spot and get some polymorphic inline caching, but maybe not.