dynamic classes and duck typing

Bill Baxter wbaxter at gmail.com
Tue Dec 1 05:46:01 PST 2009


On Tue, Dec 1, 2009 at 5:38 AM, Bill Baxter <wbaxter at gmail.com> wrote:
> On Tue, Dec 1, 2009 at 5:18 AM, Lutger <lutger.blijdestijn at gmail.com> wrote:
>> Ary Borenszweig wrote:
>>
>>> Denis Koroskin wrote:
>>>> On Tue, 01 Dec 2009 15:05:16 +0300, Ary Borenszweig
>>>> <ary at esperanto.org.ar> wrote:
>>>>
>>>>> Ary Borenszweig wrote:
>>>>>> retard wrote:
>>>>>>> Tue, 01 Dec 2009 03:16:47 -0800, Walter Bright wrote:
>>>>>>>
>>>>>>>> Ary Borenszweig wrote:
>>>>>>>>> Can you show examples of points 2, 3 and 4?
>>>>>>>> Have opDispatch look up the string in an associative array that
>>>>>>>> returns
>>>>>>>> an associated delegate, then call the delegate.
>>>>>>>>
>>>>>>>> The dynamic part will be loading up the associative array at run
>>>>>>>> time.
>>>>>>>
>>>>>>> This is not exactly what everyone of us expected. I'd like to have
>>>>>>> something like
>>>>>>>
>>>>>>> void foo(Object o) {
>>>>>>>   o.duckMethod();
>>>>>>> }
>>>>>>>
>>>>>>> foo(new Object() { void duckMethod() {} });
>>>>>>>
>>>>>>> The feature isn't very dynamic since the dispatch rules are defined
>>>>>>> statically. The only thing you can do is rewire the associative
>>>>>>> array when forwarding statically precalculated dispatching.
>>>>>>  Exactly! That's the kind of example I was looking for, thanks.
>>>>>
>>>>> Actuall, just the first part of the example:
>>>>>
>>>>> void foo(Object o) {
>>>>>     o.duckMethod();
>>>>> }
>>>>>
>>>>> Can't do that because even if the real instance of Object has an
>>>>> opDispatch method, it'll give a compile-time error because Object does
>>>>> not defines duckMethod.
>>>>>
>>>>> That's why this is something useful in scripting languages (or ruby,
>>>>> python, etc.): if the method is not defined at runtime it's an error
>>>>> unless you define the magic function that catches all. Can't do that
>>>>> in D because the lookup is done at runtime.
>>>>>
>>>>> Basically:
>>>>>
>>>>> Dynanic d = ...;
>>>>> d.something(1, 2, 3);
>>>>>
>>>>> is just a shortcut for doing
>>>>>
>>>>> d.opDispatch!("something")(1, 2, 3);
>>>>>
>>>>> (and it's actually what the compiler does) but it's a standarized way
>>>>> of doing that. What's the fun in that?
>>>>
>>>> The fun is that you can call d.foo and d.bar() even though there is no
>>>> such method/property.
>>>>
>>>> In ActionScript (and JavaScript, too, I assume), foo.bar is
>>>> auto-magically rewritten as foo["bar"]. What's fun in that?
>>>
>>> The fun is that in Javascript I can do:
>>>
>>> ---
>>> function yourMagicFunction(d) {
>>>    d.foo();
>>> }
>>>
>>> var something = fromSomewhere();
>>> yourMagicFunction(something);
>>> ---
>>>
>>> and it'll work in Javascript because there's no type-checking at
>>> compile-time (well, because there's no compile-time :P)
>>>
>>> Let's translate this to D:
>>>
>>> ---
>>> void yourMagicFunction(WhatTypeToPutHere d) {
>>>    d.foo();
>>> }
>>>
>>> auto something = fromSomewhere();
>>> yourMagicFunction(something);
>>> ---
>>>
>>> What type to put in "WhatTypeToPutHere"? If it's Object then it won't
>>> compile. If it's something that defines foo, ok. If it's something that
>>> defines opDispatch, then it's:
>>>
>>>    d.opDispatch("foo")();
>>>
>>> but you could have written it like that from the beginning.
>>>
>>> So for now I see two uses for opDispatch:
>>>
>>> 1. To create a bunch of similar functions, like the swizzle one.
>>> 2. To be able to refactor a class by moving a method to opDispatch or
>>> viceversa:
>>>
>>> class Something {
>>>    void foo() { }
>>> }
>>>
>>> can be refactored to:
>>>
>>> class Something {
>>>    void opDispatch(string name) if (name == "foo") {}
>>> }
>>>
>>> without problems on the client side either way.
>>>
>>> In brief, when you see:
>>>
>>> var x = ...;
>>> x.foo();
>>>
>>> in Javascript, you have no idea where foo could be defined.
>>>
>>> If you see the same code in D you know where to look for: the class
>>> itself, it's hierarchy, alias this, opDispatch. That's a *huge*
>>> difference.
>>
>> I don't get it, what if WhatTypeToPutHere does a dynamic lookup, then it's
>> pretty much the same a Javascript isn't it? Except that everything in
>> Javascript does dynamic lookup and in D you are restricted to types that
>> have this dynamic lookup (which, pending a phobos solution you have to code
>> yourself). Do you mean to say this 'except' is the obstacle somehow?
>>
>> To say it in code:
>>
>> void yourMagicDFunction(T)(T d)
>>  if ( ImplementsFooOrDispatch!T )
>> {
>>   d.foo(); // may (or not) be rewritten as d.opDispatch!"foo"
>> }
>>
>> In javascript I understand it is like this:
>>
>> void yourMagicJavascriptFunction(T d)
>> {
>>   d.foo(); // rewritten as d["foo"]
>> }
>>
>> But with opDisptach implemented like this it is the same in D:
>>
>> class DynamicThing
>> {
>>    void opDispatch(string name)()
>>    {
>>        auto func = this.lookupTable[name]; // looks up 'foo'
>>        func(); //
>>    }
>> }
>>
>> How is that less dynamic? You would be able to call or even redefine at
>> runtime, for example, signals defined in xml files used to build gui
>> components.
>
> It is a bit less dynamic because in D it's all done with templates.
> For instance in Javascript you can easily pass
> yourMagicJavascriptFunction around to other functions.
> And you can rebind the method by setting  d.foo = &someOtherFunction.
> Instead of d.lookupTable["foo"] = &someOtherFunction.
>
> But I'm not sure such differences make a big impact on any major class
> of use cases.

I forgot a biggie: with opDispatch you must know the return type at
compile time.
You could make the return type be Variant or something, but then that
makes it quite different from a "regular" function.
Whereas in a dynamic language like Javascript a dynamic method looks
just like a regular method (because they're all dynamic, of course).

--bb



More information about the Digitalmars-d mailing list