dynamic classes and duck typing

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Tue Dec 1 10:48:19 PST 2009


Bill Baxter wrote:
> 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

I don't think that's any difference at all. Javascript does use a sort 
of Variant for all of its values.

So if you want dynamic:

a) have opDispatch forward the string to dynDispatch as a regular 
(runtime) value, pack all parameters into Variants (or an array thereof 
- probably better, or even one Variant that in turn packs an array - 
feature recently implemented, yum), and return a Variant;

b) have dynDispatch return a Variant which will be then returned by 
opDispatch.

It's not less powerful than discussed. It's more .


Andrei



More information about the Digitalmars-d mailing list