Protocol library as alternative to refinements (Russell Leggett)

Benjamin (Inglor) Gruenbaum inglor at gmail.com
Mon Oct 21 14:52:40 PDT 2013


On Tue, Oct 22, 2013 at 12:15 AM, Russell Leggett <russell.leggett at gmail.com
> wrote:

> > 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.

This is exactly what I'm trying to do, figuring out how it acts in
different scenarios. I know better solutions come from actual usage but at
least I want to understand a behavior we can built from. I like this idea
and it seems like something that can solve issues I have when coding.

> I can see most of your examples involve the interaction between the
protocol method and a method supplied on the object itself... They
definitely complicate things... I guess I would say that I would have this
throw an error. ... Skipping foo on the object because its not a function
seems too magical.

Skipping `foo` on the object because it is not a function is too magical in
my opinion too. Working out how instance methods work in this scenario
seems like quite the task to me. The step of putting the protocol _between_
the object and the prototype sounds pretty hard to get right in particular.
I don't like thinking of reading from the prototype (as in the case of
fetching a method) any differently from reading from the own object. After
all sharing functionality is at the very core of prototypical inheritance.


>> ---- Case 3:
> 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. true - use Bar.foo

This makes some sense. About scope resolution more generally I just want to
make a note that in C# extension methods, the extension method is always
the _last_ candidate. It would check anywhere in the inheritance chain
_before_ attempting to evaluate the extension method. For example:

   ```
    public class Bar
    {
        public int GetFive() { return 5;}
    }
    public class Foo : Bar{}

    public static class FooExt
    {
        static int GetFive(this Foo bar)
        {
            return 5555;
        }
        static string ToString(this Foo bar)
        {
            return "Hi";
        }
    }
     static void Main(string[] args)
        {
            Console.WriteLine((new Foo()).GetFive()); // this prints 5
            Console.WriteLine(new Foo())); // Uses the implementation of
Object.ToString .
        }
    ```

This is a major difference between this proposal and C# extension methods.
However, I'm not sure it's bad. Would you mind making an argumnt for
prioritizing the protocol method over an object method?

>> 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.

Beautiful. This bit works out quite nicely.


On Tue, Oct 22, 2013 at 12:15 AM, Russell Leggett <russell.leggett at gmail.com
> wrote:

> 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/20131022/245dc979/attachment-0001.html>


More information about the es-discuss mailing list