Protocol library as alternative to refinements (Russell Leggett)

Russell Leggett russell.leggett at gmail.com
Tue Oct 22 10:10:38 PDT 2013


On Tue, Oct 22, 2013 at 12:53 PM, Dean Landolt <dean at deanlandolt.com> wrote:

>
>
>
> On Tue, Oct 22, 2013 at 12:44 PM, Russell Leggett <
> russell.leggett at gmail.com> wrote:
>
>>
>> Say you have an object for which you want to implement the Cowboy and
>>> Canvas protocols (to borrow /be's favorite example). Both implement a
>>> "draw" method, but when you try to import from both protocols you'll
>>> naturally have to rename one or both. Now say you want to override Cowboy's
>>> `draw` method on an instance? You'll end up clobbering the Canvas
>>> protocol's draw method with the obviously wrong function. Not cool. This
>>> can be easily corrected with Symbols.
>>>
>>>
>>
>> Yes, I'm liking this idea. Protocol always first - override through a
>> symbol. Honestly, the more I think about it, the more I think overriding
>> won't happen much and therefore isn't a huge problem, making it more
>> specific through a symbol is not a bad idea.
>>
>> Last question - what about the priority of the defaults? Are they still
>> prioritized over prototype? I was worried at first about unintentional
>> clobbering the other way, but then realized that its easy to check for the
>> method in the default if you want to prioritize the prototype over the
>> default.
>>
>>     Cowboy.defaults({
>>         draw(){
>>             if(typeof this.draw === "function"){
>>                 this.draw();
>>             }else{
>>                 //something here
>>             }
>>         }
>>     });
>>
>
>
> This is an interesting point -- the implementation could choose whether or
> not to dispatch to an instance, and how. At this point I wouldn't call them
> "defaults" since they'd always be run, and would be responsible for their
> own dispatching. I still think dispatching on strings would defeat one of
> the biggest advantages of protocols, but this approach is flexible enough
> to allow that. Also, it doesn't try to intercede between own and prototype
> lookup, which is much nicer.
>
>
The reason they are called defaults is because they are a fallback for when
the protocol isn't specified for a specific type. If I have two types A and
B. And I have a protocol P. P has a method "foo".

    P.defaults({
        foo:function(){
            console.log("default foo");
        }
    });
    P.extends(A,{
        foo:function(){
            console.log("A's foo");
        }
    })
    let a = new A();
    a::foo(); //outputs 'A's foo'
    let b = new B(); //outputs 'default foo'

Basically, the default is useful for:

   - generic methods that only depend on other protocol methods
   - methods that want to do introspection on the object manually instead
   of dispatching on type
   - cases with a sensible backup

Just to be clear, default implementations are totally optional. A protocol
can have zero or more of them. I had originally been thinking that the
default should be last, allowing for a prototype to go first, but if the
default goes first, then it has the opportunity to defer to the prototype
*or* ignore the prototype.

Revised algorithm:

   1. If receiver has protocol method symbol as a property, use that as
   override.
   2. Try to use protocol methods - start by checking receiver type
   mapping, then check up type hierarchy for any matches, and finally if no
   matches, use the default if defined.
   3. Finally, if no matches and no default, check prototype for method of
   same name.


Does that sound better?

- Russ
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20131022/a8cffd44/attachment.html>


More information about the es-discuss mailing list