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.
On Mon, Oct 21, 2013 at 3:17 PM, Benjamin (Inglor) Gruenbaum < inglor at gmail.com> wrote: > Russell Leggett <russell.leggett at gmail.com> wrote: > > https://gist.github.com/genericallyloud/7086380 > > Very interesting. > > > // 4. use the default if available > > 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: 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. - Russ -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20131021/5439b498/attachment-0001.html>