December 01, 2009
Steven Schveighoffer 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

Yes, we need to implement that. Essentially the pipe dream is to add opDispatch to Variant and have it accept any call that would go through the contained type.

These are heady days for D!


Andrei
December 01, 2009
Steven Schveighoffer 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

obj.dynDispatch(var);


Andrei
December 01, 2009
Lutger wrote:
> In javascript I understand it is like this:
> 
> void yourMagicJavascriptFunction(T d)
> {
>    d.foo(); // rewritten as d["foo"]
> }

d.foo is rewritten as d["foo"],

d.foo() is rewritten as d["foo"]()
December 01, 2009
On Tue, 01 Dec 2009 13:50:38 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> 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.

It is unlikely that anything other than symbols are expected for opDispatch, I can't think of an example that would not want to put the isValidSymbol constraint on the method.

An example of abuse:

struct caseInsensitiveWrapper(T)
{
   T _t;
   auto opDispatch(string fname, A...) (A args)
   {
      mixin("return _t." ~ toLower(fname) ~ "(args);");
   }
}

class C { int x; void foo(); }

caseInsensitiveWrapper!(C) ciw;
ciw._t = new C;
ciw.opDispatch!("x = 5, delete _t, _t.foo")();

I don't know if this is anything to worry about, but my preference as an author for caseInsensitiveWrapper is that this last line should never compile without any special requirements from me.

>
>> 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?

Isn't opBinary almost identical to opDispatch?  The only difference I see is that opBinary works with operators as the 'symbol' and dispatch works with valid symbols.  Is it important to distinguish between operators and custom dispatch?

-Steve
December 01, 2009
Bill Baxter wrote:
> 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).


The Javascript implementations use variants for all variables, values, and function returns. So it isn't any different from defining opDispatch to take and return Variant's.

std.variant needs to be extended with opDispatch so it can execute a call operation on a Variant, then it will be very very similar to Javascript.
December 01, 2009
Andrei Alexandrescu wrote:
> 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 .

Yes, I think you're right that the parameters passed should be a Variant[], not variadic.

BTW, folks, please when replying cut down the quoting!
December 01, 2009
On Tue, Dec 01, 2009 at 11:07:15AM -0800, Walter Bright wrote:
> std.variant needs to be extended with opDispatch so it can execute a call operation on a Variant, then it will be very very similar to Javascript.

I looked into this for a few minutes this morning. Variant already stores delegates, so all that needs to be done is the existing opCall needs to be renamed (easy enough. Maybe it could become a constructor?) and then implemented to forward its arguments to the inner delegate.

That's the tricky part, and I haven't had the time to figure that out yet.

-- 
Adam D. Ruppe
http://arsdnet.net
December 01, 2009
Walter Bright wrote:
> Andrei Alexandrescu wrote:
>> 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 .
> 
> Yes, I think you're right that the parameters passed should be a Variant[], not variadic.

Parameters to dynDispatch (the user-defined forwarding function), NOT opDispatch. opDispatch can take _anything_.

Sorry if I'm repeating what you know already, but I am obsessing over a small misunderstanding could end up hamstringing this very powerful feature.

So: opDispatch has absolutely no restrictions except a string in the first static parameters position.


Andrei
December 01, 2009
Bill Baxter wrote:
> On Tue, Dec 1, 2009 at 5:18 AM, Lutger <lutger.blijdestijn@gmail.com> wrote:
>> Ary Borenszweig wrote:

>>>>>>> The feature isn't very dynamic since the dispatch rules are defined
>>>>>>> statically. The only thing you can do is rewire the associative

>> 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?
>>

>> 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.

It's a helluva lot more dynamic in D because it can do code generation on request. The "dynamic" bit in Javascript is really an AA lookup, + reflection.
December 01, 2009
On Tue, Dec 1, 2009 at 11:43 AM, Don <nospam@nospam.com> wrote:
> Bill Baxter wrote:
>>
>> On Tue, Dec 1, 2009 at 5:18 AM, Lutger <lutger.blijdestijn@gmail.com> wrote:
>>>
>>> Ary Borenszweig wrote:
>
>>>>>>>> The feature isn't very dynamic since the dispatch rules are defined statically. The only thing you can do is rewire the associative
>
>>> 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?
>>>
>
>>> 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.
>
> It's a helluva lot more dynamic in D because it can do code generation on request. The "dynamic" bit in Javascript is really an AA lookup, + reflection.

But that's code generation /at compile time/.
You can call that "more dynamic" if you like, but it seems to fall
more in the realm of what is considered "static" to me.
Doesn't mean it's not really useful, but calling it dynamic seems to
be stretching the traditional definition a bit too far.

--bb