Protocol library as alternative to refinements (Russell Leggett)

Russell Leggett russell.leggett at gmail.com
Mon Oct 21 14:15:59 PDT 2013


I'll preface this by saying that I haven't made a formal proposal and this
isn't an actual library. You're doing a good job of spotting some undefined
behavior which would probably be better defined by trying it out. I'll give
my opinions on them, but it could all use a good test drive before coming
down on these.

To help the discussion I'll paste the basic algorithm I outlined:

1. if the receiver has an own property of the same name, use that
2. if the receiver's type matches an extension of the protocol, use the
protocol method
3. if the receiver has a method of the same name somewhere up the prototype
chain, use that
4. use the default if available


> ----- Case 1:
>
> I have an object O of type Foo. A protocol P.
>
>  - O has the structure {x:5,foo:7};
>  - The protocol implements `foo` but does not specifically for Foo (via
> .defaults).
>
> What happens? Does `P.foo` get invoked, or do we get an error because
> `O.foo` is not a function?
>

I can see most of your examples involve the interaction between the
protocol method and a method supplied on the object itself. Clojure
protocols don't have this type of interaction. I tossed them in because
they seemed like they would work well with some of the examples brought up
in the other thread. They definitely complicate things... I guess I would
say that I would have this throw an error. Logically to me, either the an
error should be thrown because it would try to invoke foo on the object, or
we should give up on the idea of falling back on the object. Skipping foo
on the object because its not a function seems too magical.

So here, O has an own property, so #1 and blows up


>
> ---- Case 2:
>
> I have an object O of type Foo, Foo.prototype = new Bar. A protocol P.
>
>  - O has the structure {x:5,foo:7};
>  - The protocol implements `foo` for Bar specifically (but not for Foo)
>
> What happens?  (Similar to case above?)
>

Same as above - error (or drop the feature)


>
> ---- Case 3:
>
> I have an object O of type Foo, Foo.prototype = new Bar. A protocol P.
>
>  - O has the structure {x:5,y:7};
>  - Bar has a method foo
>  - The protocol implements `foo` for Bar specifically (but not for Foo)
>
> What happens? Does it invoke Bar.foo or P.foo?
>

Ah, yes, I had thought about this a bit, but it had never made it into my
gist at all. Let me revise my algorithm:
    4. Check up type chain for match
    5. If method defined on protocol default, use that
    6. Otherwise error

1. false, continue
2. false, continue
3. false, continue
4. true - use Bar.foo


>
> ---- Case 4:
>
> I have an object O of type Foo, Foo.prototype = new Bar. A protocol P.
>
>  - O has the structure {x:5,y:7};
>  - Bar has a method foo
>  - The protocol implements `foo` for Bar specifically (but not for Foo)
>
> What happens? Does it invoke Bar.foo or P.foo ?
>

This looks the same as 3 to me, so Bar.foo


>
> ---- Case 5:
>
> I have an object O of type Foo, I import two `Protocol`s that implement a
> method `Foo` at the same specificity level - what happens?
>

This is an easy one and comes down to the benefits of making use of normal
variables and lexical scoping. Remember that protocols don't affect the
types at all, and the protocols exist completely independently of each
other. If you imported two protocols A and B that each have a method 'foo'
defined for type Foo, the only thing you would have to be careful of is
redefining your variables accidentally.

    import {foo} from 'A';
    import {foo} from 'B';

This is going to be a problem no matter what you're doing. You are
importing two things with the same name, trying to introduce to variables
with the same name. There's no magic for protocols here, you can just alias
your imports to avoid name clashes.

    import {foo as fooA} from 'A';
    import {foo as fooB} from 'B';

    o::fooA();
    o::fooB();

Alternatively, if the have the protocol itself, you can access the methods
directly and do:

    o::A.methods.foo();
    o::B.methods.foo();

Which isn't as nice, but is an option.

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


More information about the es-discuss mailing list