dynamic classes and duck typing

George Moss rolling-stone at gathers-no-moss.org
Tue Dec 1 06:23:39 PST 2009


Lutger wrote:
> 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.

So the return type is now suggested to be Variant.  Plausible 
expectation is that Variant is now input as argument to some another 
function.

So now you have a Variant to deal with as a function argument.  How now 
is Variant argument to be dealt with?  Question meaning typeswitch or 
something else?



More information about the Digitalmars-d mailing list