dynamic classes and duck typing

Lutger lutger.blijdestijn at gmail.com
Tue Dec 1 06:09:13 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 understand, thanks for the clarifications. 

Variant doesn't sound too bad. I guess it's just the consequence of not 
overloading by return type. 

What I like about this solution is the leeway you have in how much 
typechecking opDispatch does. You can make the return type Variant and the 
parameters a variadics of Variant (is that a word?), but also define the 
signature opDispatch can accept precisely or through template constraints. 
You can even check the dispatched symbol at compile time (no dynamism at 
all).

Obviously opDispatch can add some dynamism to D, I guess we'll see how it 
pans out.



More information about the Digitalmars-d mailing list