View mode: basic / threaded / horizontal-split · Log in · Help
December 01, 2009
Re: dynamic classes and duck typing
On Tue, 01 Dec 2009 10:25:43 -0500, Denis Koroskin <2korden@gmail.com>  
wrote:

> On Tue, 01 Dec 2009 17:12:38 +0300, Steven Schveighoffer  
> <schveiguy@yahoo.com> wrote:
>
>> On Tue, 01 Dec 2009 08:49:58 -0500, Denis Koroskin <2korden@gmail.com>  
>> wrote:
>>
>>> On Tue, 01 Dec 2009 16:46:25 +0300, Steven Schveighoffer  
>>> <schveiguy@yahoo.com> wrote:
>>>
>>>> On Mon, 30 Nov 2009 23:32:21 -0500, Bill Baxter <wbaxter@gmail.com>  
>>>> wrote:
>>>>
>>>>> On Mon, Nov 30, 2009 at 7:12 PM, Walter Bright
>>>>> <newshound1@digitalmars.com> wrote:
>>>>>> Bill Baxter wrote:
>>>>>>>
>>>>>>> So we can overload on @property-ness?
>>>>>>
>>>>>> No.
>>>>>>
>>>>>>> I.e. this works
>>>>>>>
>>>>>>> struct S
>>>>>>> {
>>>>>>> @property
>>>>>>> float x() { return 1.0f; }
>>>>>>> float x() { return 2.0f; }
>>>>>>> }
>>>>>>>
>>>>>>> void main()
>>>>>>> {
>>>>>>>    S  s;
>>>>>>>    writefln("%s", s.x); // writes 1.0
>>>>>>>    writefln("%s", s.x()); // writes 2.0
>>>>>>> }
>>>>>>
>>>>>> That just looks wrong.
>>>>>>
>>>>>
>>>>> Ok, so you can't have both dynamic properties and dynamic methods  
>>>>> with
>>>>> this.  One or the other, your pick.
>>>>> Seems like an unfortunate limitation.
>>>>
>>>>
>>>> what a minute, can't you use template conditionals to distinguish?   
>>>> i.e. I would expect this to work:
>>>>
>>>> struct S
>>>> {
>>>>    @property float opDispatch(string s)() if (s == "x") {return 1.0f;}
>>>>    float opDispatch(string s)() { return 2.0f;}
>>>> }
>>>>
>>>> void main()
>>>> {
>>>>    S s;
>>>>    writefln("%s", s.x); // 1.0
>>>>    writefln("%s", s.y()); // 2.0
>>>> }
>>>>
>>>> Overloading opDispatch based on the called symbol name should always  
>>>> be possible, and overloading on parameter types is always possible.
>>>>
>>>> -Steve
>>>
>>> What if you don't know argument names a-priori? Consider a generic  
>>> Dynamic class that has nothing but a single opDispatch method.
>>
>> although opDispatch allows some dynamic function definitions, the  
>> *usage* of opDispatch is always static.  The question is, if you are  
>> for example wrapping another type, can you introspect the attributes of  
>> its methods?
>>
>> For example, I'd expect something like this should be possible in the  
>> future:
>>
>> struct Wrapper(T)
>> {
>>     T t;
>>     @property auto opDispatch(string s)() if(isProperty!T(s) )  
>> {mixin("return t." ~ s ~ ";");} // getters
>>     @property auto opDispatch(string s, A)(A arg) if(isProperty!T(s) )  
>> {mixin("return (t." ~ s ~ " = arg);"); } // setters
>>     auto opDispatch(string s, A...)(A args) { mixin("return t." ~ s ~  
>> "(args);");}
>> }
>>
>> Now, given the function attributes that are possible (this does not  
>> include const and immutable, which are overloaded via parameter types),  
>> this is going to get pretty ugly quickly.  Unfortunately, the  
>> attributes are not decided by the caller, but by the callee, so you  
>> have to use template conditionals.  It would be nice if there was a way  
>> to say "copy the attributes from function x" when defining template  
>> functions in a way that doesn't involve conditionals, but even then,  
>> you would have a hard time defining such usage because you don't know  
>> what function you want until you evaluate the template string.
>>
>> -Steve
>
> I might work with your design, but it will lead to considerable code  
> bloat, and it's not that static after all.
> I'd say that you could achieve the same with method forwarding using  
> alias this:
>
> struct Wrapper(T)
> {
>      T t;
>      alias this t;
> }
>
> The true power of opDispatch comes with a fully Dynamic type, that has  
> no type information until runtime:
>
> void foo(Dynamic duck)
> {
>     duck.quack():
> }

You are missing the point of opDispatch.  It is not runtime defined,  
because the compiler statically decides to call opDispatch.  The dynamic  
part of opDispatch comes if you want to do something based on runtime  
values within the opDispatch function.  e.g. the compiler doesn't decide  
at *runtime* whether to call opDispatch or some normal function named  
quack, it's decided at compile time.  opDispatch could be completely  
compile-time defined since it is a template.  But the 'dynamicness' of it  
is basically no more dynamic than a normal function which does something  
based on runtime values.

Compare that to a dynamic language with which you can add methods to any  
object instance to make it different than another object, or make it  
conform to some interface.

My example is not a complete example BTW.  You can do much more than just  
dispatch to a sub-type, you can do other things that alias this cannot.   
For example, you could log each call to a function before calling the  
sub-type.  But there are probably even better ways to do that with  
mixins.  The real power of opDispatch comes when you don't want the  
default mapping of case-sensitive function name to implementation.

-Steve
December 01, 2009
Re: dynamic classes and duck typing
On Tue, 01 Dec 2009 19:02:27 +0300, Steven Schveighoffer  
<schveiguy@yahoo.com> wrote:

> On Tue, 01 Dec 2009 10:25:43 -0500, Denis Koroskin <2korden@gmail.com>  
> wrote:
>
>> On Tue, 01 Dec 2009 17:12:38 +0300, Steven Schveighoffer  
>> <schveiguy@yahoo.com> wrote:
>>
>>> On Tue, 01 Dec 2009 08:49:58 -0500, Denis Koroskin <2korden@gmail.com>  
>>> wrote:
>>>
>>>> On Tue, 01 Dec 2009 16:46:25 +0300, Steven Schveighoffer  
>>>> <schveiguy@yahoo.com> wrote:
>>>>
>>>>> On Mon, 30 Nov 2009 23:32:21 -0500, Bill Baxter <wbaxter@gmail.com>  
>>>>> wrote:
>>>>>
>>>>>> On Mon, Nov 30, 2009 at 7:12 PM, Walter Bright
>>>>>> <newshound1@digitalmars.com> wrote:
>>>>>>> Bill Baxter wrote:
>>>>>>>>
>>>>>>>> So we can overload on @property-ness?
>>>>>>>
>>>>>>> No.
>>>>>>>
>>>>>>>> I.e. this works
>>>>>>>>
>>>>>>>> struct S
>>>>>>>> {
>>>>>>>> @property
>>>>>>>> float x() { return 1.0f; }
>>>>>>>> float x() { return 2.0f; }
>>>>>>>> }
>>>>>>>>
>>>>>>>> void main()
>>>>>>>> {
>>>>>>>>    S  s;
>>>>>>>>    writefln("%s", s.x); // writes 1.0
>>>>>>>>    writefln("%s", s.x()); // writes 2.0
>>>>>>>> }
>>>>>>>
>>>>>>> That just looks wrong.
>>>>>>>
>>>>>>
>>>>>> Ok, so you can't have both dynamic properties and dynamic methods  
>>>>>> with
>>>>>> this.  One or the other, your pick.
>>>>>> Seems like an unfortunate limitation.
>>>>>
>>>>>
>>>>> what a minute, can't you use template conditionals to distinguish?   
>>>>> i.e. I would expect this to work:
>>>>>
>>>>> struct S
>>>>> {
>>>>>    @property float opDispatch(string s)() if (s == "x") {return  
>>>>> 1.0f;}
>>>>>    float opDispatch(string s)() { return 2.0f;}
>>>>> }
>>>>>
>>>>> void main()
>>>>> {
>>>>>    S s;
>>>>>    writefln("%s", s.x); // 1.0
>>>>>    writefln("%s", s.y()); // 2.0
>>>>> }
>>>>>
>>>>> Overloading opDispatch based on the called symbol name should always  
>>>>> be possible, and overloading on parameter types is always possible.
>>>>>
>>>>> -Steve
>>>>
>>>> What if you don't know argument names a-priori? Consider a generic  
>>>> Dynamic class that has nothing but a single opDispatch method.
>>>
>>> although opDispatch allows some dynamic function definitions, the  
>>> *usage* of opDispatch is always static.  The question is, if you are  
>>> for example wrapping another type, can you introspect the attributes  
>>> of its methods?
>>>
>>> For example, I'd expect something like this should be possible in the  
>>> future:
>>>
>>> struct Wrapper(T)
>>> {
>>>     T t;
>>>     @property auto opDispatch(string s)() if(isProperty!T(s) )  
>>> {mixin("return t." ~ s ~ ";");} // getters
>>>     @property auto opDispatch(string s, A)(A arg) if(isProperty!T(s) )  
>>> {mixin("return (t." ~ s ~ " = arg);"); } // setters
>>>     auto opDispatch(string s, A...)(A args) { mixin("return t." ~ s ~  
>>> "(args);");}
>>> }
>>>
>>> Now, given the function attributes that are possible (this does not  
>>> include const and immutable, which are overloaded via parameter  
>>> types), this is going to get pretty ugly quickly.  Unfortunately, the  
>>> attributes are not decided by the caller, but by the callee, so you  
>>> have to use template conditionals.  It would be nice if there was a  
>>> way to say "copy the attributes from function x" when defining  
>>> template functions in a way that doesn't involve conditionals, but  
>>> even then, you would have a hard time defining such usage because you  
>>> don't know what function you want until you evaluate the template  
>>> string.
>>>
>>> -Steve
>>
>> I might work with your design, but it will lead to considerable code  
>> bloat, and it's not that static after all.
>> I'd say that you could achieve the same with method forwarding using  
>> alias this:
>>
>> struct Wrapper(T)
>> {
>>      T t;
>>      alias this t;
>> }
>>
>> The true power of opDispatch comes with a fully Dynamic type, that has  
>> no type information until runtime:
>>
>> void foo(Dynamic duck)
>> {
>>     duck.quack():
>> }
>
> You are missing the point of opDispatch.  It is not runtime defined,  
> because the compiler statically decides to call opDispatch.  The dynamic  
> part of opDispatch comes if you want to do something based on runtime  
> values within the opDispatch function.  e.g. the compiler doesn't decide  
> at *runtime* whether to call opDispatch or some normal function named  
> quack, it's decided at compile time.  opDispatch could be completely  
> compile-time defined since it is a template.  But the 'dynamicness' of  
> it is basically no more dynamic than a normal function which does  
> something based on runtime values.
>
> Compare that to a dynamic language with which you can add methods to any  
> object instance to make it different than another object, or make it  
> conform to some interface.
>

Well, I believe it's possible to implement the same with opDispatch (not  
just to any object, but to those that support it):

void foo() {}

Dynamic d = ..;
if (!d.foo) {
    d.foo = &foo;
}

d.foo();
December 01, 2009
Re: dynamic classes and duck typing
On 2009-12-01 07:01:20 -0500, Ary Borenszweig <ary@esperanto.org.ar> said:

> Foo foo = new Bar();
> foo.something();
> 
> will not work as expected because something() will be bound to Foo's 
> opDispatch and it isn't a virtual method. Of course you can make 
> opDispatch invoke a virtual function and override that function in Bar, 
> but since there isn't a standard name or method for doing this everyone 
> will start doing it their way (I don't like it when there's no 
> standarization for well-known operations) and it looks like a hack.

Someone ought to make std.dispatch and create that standardized runtime 
dispatch system.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
December 01, 2009
Re: dynamic classes and duck typing
On Tue, 01 Dec 2009 11:20:06 -0500, Denis Koroskin <2korden@gmail.com>  
wrote:

> On Tue, 01 Dec 2009 19:02:27 +0300, Steven Schveighoffer  
> <schveiguy@yahoo.com> wrote:
>
>>
>> You are missing the point of opDispatch.  It is not runtime defined,  
>> because the compiler statically decides to call opDispatch.  The  
>> dynamic part of opDispatch comes if you want to do something based on  
>> runtime values within the opDispatch function.  e.g. the compiler  
>> doesn't decide at *runtime* whether to call opDispatch or some normal  
>> function named quack, it's decided at compile time.  opDispatch could  
>> be completely compile-time defined since it is a template.  But the  
>> 'dynamicness' of it is basically no more dynamic than a normal function  
>> which does something based on runtime values.
>>
>> Compare that to a dynamic language with which you can add methods to  
>> any object instance to make it different than another object, or make  
>> it conform to some interface.
>>
>
> Well, I believe it's possible to implement the same with opDispatch (not  
> just to any object, but to those that support it):
>
> void foo() {}
>
> Dynamic d = ..;
> if (!d.foo) {
>      d.foo = &foo;
> }
>
> d.foo();

You could do something like this (I don't think your exact syntax would  
work), but you could also do something like this without opDispatch.   But  
the name 'foo' is still statically decided.  Note that opDispatch doesn't  
implement this ability for you, you still have to implement the dynamic  
calls behind it.  The special nature of opDispatch is how you can define  
how to map any symbol to any implementation without having to explicitly  
use strings.  In fact, opDispatch is slightly less powerful than such a  
method if the method uses a runtime string for dispatch.

For example, in php, I can do this:

foo($var)
{
   $obj->$var();
}

The equivalent in D would be:

foo(string var)
{
   obj.opDispatch!(var)();
}

This I would consider to be true runtime-decided dispatch.

-Steve
December 01, 2009
Re: dynamic classes and duck typing
On Tue, 01 Dec 2009 19:41:46 +0300, Steven Schveighoffer  
<schveiguy@yahoo.com> wrote:

> On Tue, 01 Dec 2009 11:20:06 -0500, Denis Koroskin <2korden@gmail.com>  
> wrote:
>
>> On Tue, 01 Dec 2009 19:02:27 +0300, Steven Schveighoffer  
>> <schveiguy@yahoo.com> wrote:
>>
>>>
>>> You are missing the point of opDispatch.  It is not runtime defined,  
>>> because the compiler statically decides to call opDispatch.  The  
>>> dynamic part of opDispatch comes if you want to do something based on  
>>> runtime values within the opDispatch function.  e.g. the compiler  
>>> doesn't decide at *runtime* whether to call opDispatch or some normal  
>>> function named quack, it's decided at compile time.  opDispatch could  
>>> be completely compile-time defined since it is a template.  But the  
>>> 'dynamicness' of it is basically no more dynamic than a normal  
>>> function which does something based on runtime values.
>>>
>>> Compare that to a dynamic language with which you can add methods to  
>>> any object instance to make it different than another object, or make  
>>> it conform to some interface.
>>>
>>
>> Well, I believe it's possible to implement the same with opDispatch  
>> (not just to any object, but to those that support it):
>>
>> void foo() {}
>>
>> Dynamic d = ..;
>> if (!d.foo) {
>>      d.foo = &foo;
>> }
>>
>> d.foo();
>
> You could do something like this (I don't think your exact syntax would  
> work), but you could also do something like this without opDispatch.    
> But the name 'foo' is still statically decided.  Note that opDispatch  
> doesn't implement this ability for you, you still have to implement the  
> dynamic calls behind it.  The special nature of opDispatch is how you  
> can define how to map any symbol to any implementation without having to  
> explicitly use strings.  In fact, opDispatch is slightly less powerful  
> than such a method if the method uses a runtime string for dispatch.
>
> For example, in php, I can do this:
>
> foo($var)
> {
>     $obj->$var();
> }
>
> The equivalent in D would be:
>
> foo(string var)
> {
>     obj.opDispatch!(var)();
> }
>
> This I would consider to be true runtime-decided dispatch.
>
> -Steve

As pointed out, ActionScript and JavaScript use foo.bar and foo["bar"]  
interchangeably, so I believe we could do something similar.

I believe there is no real difference between d.foo and d.bar for  
opDispatch (except that it could calculate string hash at compile time for  
faster hast-table lookup), and it would just call a generic run-time  
method anyway. As such, this method could be made visible to everyone:

class Dynamic
{
    // getter
    @property Dynamic opDispatch(string prop)
    {
        return this[prop];
    }

    // setter
    @property void opDispatch(string prop)(Dynamic value)
    {
        this[prop] = value;
    }

    ref Dynamic opIndex(string propName)
    {
        // do a hash-table lookup
    }

    Dynamic opCall(Args...)(Args args)
    {
        // do magic
    }
}

So essentially, opDispatch is just a syntax sugar. But it's very important  
one, because not only it makes writing code easier, it would allow using  
dynamic objects with generic algorithms.

Note that only @property version of opDispatch is really needed, method  
invokation is covered by @property + opCall pair.

And it's the opCall implementation that bothers me the most... I don't see  
any way to implement it without reflection ATM.
December 01, 2009
Re: dynamic classes and duck typing
On Tue, 01 Dec 2009 11:58:43 -0500, Denis Koroskin <2korden@gmail.com>  
wrote:

> On Tue, 01 Dec 2009 19:41:46 +0300, Steven Schveighoffer  
> <schveiguy@yahoo.com> wrote:
>
>> On Tue, 01 Dec 2009 11:20:06 -0500, Denis Koroskin <2korden@gmail.com>  
>> wrote:
>>
>>> On Tue, 01 Dec 2009 19:02:27 +0300, Steven Schveighoffer  
>>> <schveiguy@yahoo.com> wrote:
>>>
>>>>
>>>> You are missing the point of opDispatch.  It is not runtime defined,  
>>>> because the compiler statically decides to call opDispatch.  The  
>>>> dynamic part of opDispatch comes if you want to do something based on  
>>>> runtime values within the opDispatch function.  e.g. the compiler  
>>>> doesn't decide at *runtime* whether to call opDispatch or some normal  
>>>> function named quack, it's decided at compile time.  opDispatch could  
>>>> be completely compile-time defined since it is a template.  But the  
>>>> 'dynamicness' of it is basically no more dynamic than a normal  
>>>> function which does something based on runtime values.
>>>>
>>>> Compare that to a dynamic language with which you can add methods to  
>>>> any object instance to make it different than another object, or make  
>>>> it conform to some interface.
>>>>
>>>
>>> Well, I believe it's possible to implement the same with opDispatch  
>>> (not just to any object, but to those that support it):
>>>
>>> void foo() {}
>>>
>>> Dynamic d = ..;
>>> if (!d.foo) {
>>>      d.foo = &foo;
>>> }
>>>
>>> d.foo();
>>
>> You could do something like this (I don't think your exact syntax would  
>> work), but you could also do something like this without opDispatch.    
>> But the name 'foo' is still statically decided.  Note that opDispatch  
>> doesn't implement this ability for you, you still have to implement the  
>> dynamic calls behind it.  The special nature of opDispatch is how you  
>> can define how to map any symbol to any implementation without having  
>> to explicitly use strings.  In fact, opDispatch is slightly less  
>> powerful than such a method if the method uses a runtime string for  
>> dispatch.
>>
>> For example, in php, I can do this:
>>
>> foo($var)
>> {
>>     $obj->$var();
>> }
>>
>> The equivalent in D would be:
>>
>> foo(string var)
>> {
>>     obj.opDispatch!(var)();
>> }
>>
>> This I would consider to be true runtime-decided dispatch.
>>
>> -Steve
>
> As pointed out, ActionScript and JavaScript use foo.bar and foo["bar"]  
> interchangeably, so I believe we could do something similar.
>
> I believe there is no real difference between d.foo and d.bar for  
> opDispatch (except that it could calculate string hash at compile time  
> for faster hast-table lookup), and it would just call a generic run-time  
> method anyway. As such, this method could be made visible to everyone:
>
> class Dynamic
> {
>      // getter
>      @property Dynamic opDispatch(string prop)
>      {
>          return this[prop];
>      }
>
>      // setter
>      @property void opDispatch(string prop)(Dynamic value)
>      {
>          this[prop] = value;
>      }
>
>      ref Dynamic opIndex(string propName)
>      {
>          // do a hash-table lookup
>      }
>
>      Dynamic opCall(Args...)(Args args)
>      {
>          // do magic
>      }
> }

This is a very nice example, I only see one minor problem with it:  the  
"do a hash table lookup" has to tentatively add an element if one doesn't  
yet exist.

However, opDispatch is even less runtime-decided in this example (it can  
always be inlined).

> So essentially, opDispatch is just a syntax sugar. But it's very  
> important one, because not only it makes writing code easier, it would  
> allow using dynamic objects with generic algorithms.

Essentially you could say opDispatch is dynamic at compile time.  Runtime,  
not so much.  But anything decided at compile time can be forwarded to a  
runtime function.

Without opDispatch, you already can get dynamic runtime function calling  
via a similar method you outline above (I didn't think of using the array  
syntax, and I've been using Javascript quite a bit lately!), but you can't  
get dynamic function calling that's drop-in replaceable with normal  
function calling at compile time without opDispatch.  I like that  
explanation.  It is probably the most compelling usage for opDispatch.

-Steve
December 01, 2009
Re: dynamic classes and duck typing
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.

Walter is right. But as it seems there is a lot of confusion about the 
feature, maybe we didn't define the feature (which is very general and 
powerful and as dynamic as you ever want to make it) in a palatable way.

Ideas?


Andrei
December 01, 2009
Re: dynamic classes and duck typing
retard wrote:
> Tue, 01 Dec 2009 14:30:43 +0300, Denis Koroskin wrote:
> 
>> On Tue, 01 Dec 2009 14:26:04 +0300, retard <re@tard.com.invalid> 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.
>> I believe you should distinguish duck types from other types.
>>
>> You shouldn't be able to call duckMethod given a reference to Object,
>> it's a statically-typed language, after all.
> 
> Agreed. But this new feature is a bit confusing - there isn't anything 
> dynamic in it. It's more or less a compile time rewrite rule. It becomes 
> dynamic when all of that can be done on runtime and there are no 
> templates involved.

Yes, that's done via old-school forwarding.

Andrei
December 01, 2009
Re: dynamic classes and duck typing
Bill Baxter wrote:
> On Tue, Dec 1, 2009 at 5:38 AM, Bill Baxter <wbaxter@gmail.com> wrote:
>> On Tue, Dec 1, 2009 at 5:18 AM, Lutger <lutger.blijdestijn@gmail.com> wrote:
>>> Ary Borenszweig wrote:
>>>
>>>> Denis Koroskin wrote:
>>>>> On Tue, 01 Dec 2009 15:05:16 +0300, Ary Borenszweig
>>>>> <ary@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
December 01, 2009
Re: dynamic classes and duck typing
Steven Schveighoffer wrote:
> On Sat, 28 Nov 2009 18:36:07 -0500, Walter Bright 
> <newshound1@digitalmars.com> wrote:
> 
>> And here it is (called opDispatch, Michel Fortin's suggestion):
>>
>> http://www.dsource.org/projects/dmd/changeset?new=trunk%2Fsrc@268&old=trunk%2Fsrc@267 
>>
> 
> I have a few questions:
> 
> 1. How should the compiler restrict opDispatch's string argument?  i.e. 
> if I implement opDispatch, I'm normally expecting the string to be a 
> symbol, but one can directly call opDispatch with any string (I can see 
> clever usages which compile but for instance circumvent const or 
> something), forcing me to always constrain the string argument, i.e. 
> always have isValidSymbol(s) in my constraints.  Should the compiler 
> restrict the string to always being a valid symbol name (or operator, 
> see question 2)?

Where in doubt, acquire more power :o). I'd say no checks; let user code 
do that or deal with those cases.

> 2. Can we cover templated operators with opDispatch?  I can envision 
> something like this:
> 
> opDispatch(string s)(int rhs) if(s == "+") {...}

How do you mean that?


Andrei
7 8 9 10 11 12 13 14 15
Top | Discussion index | About this forum | D home