April 17, 2009
On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl@nospam.org> wrote:

> 在 Fri, 17 Apr 2009 23:20:53 +0800,davidl <davidl@nospam.org> 写道:
>
>> 在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:
>>
>>> On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax@gmail.com> wrote:
>>>
>>>> I don't fully understand the example though. In writefln((v.qq = 5).i),
>>>> how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate
>>>> the 5 to the new B()?
>>>
>>> I think it translates to
>>>
>>> opDotExp("qq") = 5
>>>
>>> Without knowing the signature of qq, how is the compiler supposed to infer that it is a property?  In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.
>>>
>>> I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges.  It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
>>>
>>
>> Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).
>>
>>
>
> DDBI can also benefit from it.
>
> Consider the use case:
> myRow.Col1 = "abc";

Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper.

Plus it's not terribly hard to write:

myRow.set("Col1", "abc");

I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.

-Steve
April 17, 2009
在 Fri, 17 Apr 2009 23:27:38 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:

> On Fri, 17 Apr 2009 11:11:55 -0400, davidl <davidl@nospam.org> wrote:
>
>> 在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:
>>
>>> On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax@gmail.com> wrote:
>>>
>>>> I don't fully understand the example though. In writefln((v.qq = 5).i),
>>>> how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate
>>>> the 5 to the new B()?
>>>
>>> I think it translates to
>>>
>>> opDotExp("qq") = 5
>>>
>>> Without knowing the signature of qq, how is the compiler supposed to infer that it is a property?  In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.
>>>
>>
>> The opDotExp overload func is supposed to deal with that, because it's in your hand to deal with the dynamic properties. The example here is illustrating the dynamic properties.
>
> except, you can't define a property like:
>
> void prop(int x)
> {
>     _prop = x ^ ~0;
> }
>
> Using a dynamic method.
>

But if you want a dynamic property, you won't want to do it in that way.
You actually make the opDot to do:

void opDot(char[] methodname, ...)
{
  if (methodname = "prop")
  {
    // deal with the vararg to get the int x
    // assign it to _prop, then you're done.
    // or you can call the prop func here by reconstructing the vararg.
  }
}

Notice that if statement can be done by a delegate. Thus when you add a property you simply add your delegate func to the class. And opDot call those delegates one by one.

>>
>>> I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges.  It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
>>>
>>> class c
>>> {
>>>    void opDotExp(char[] methodname,...)
>>>    {
>>>       if(methodname == "mymethod")
>>>          callMyMethod();
>>>       else
>>>          throw new Exception("bad method name: " ~ methodname);
>>>    }
>>> }
>>>
>>> void foo(c myc, bool rarelySetToTrue)
>>> {
>>>    if(rarelySetToTrue)
>>>      myc.mymethud(); // compiles, will throw runtime exception
>>> }
>>>
>>
>> The problem is you're dealing with the class which is overloaded its opDot. You know the risk before hand, you are not going to overload for every classes. Here, you seem to little bit overrate this feature. :)
>> If you want things checked, then you probabely need to go back to static. This dynamic stuff is used for dynamic things only, and as long as you have to do it in the dynamic way that means you have no easy way or even impossible to check it at compiletime and you accept the potential risk like the example you posted.
>
> Sure, but what is the reason to need dynamic methods?  I'm just trying to understand the usefulness of it.  If a method is dynamic, we lose the following things:
>
> - compile-time type/signature checking
> - IDE assistance in determining which methods are available
> - ease of tracing where a method call goes.
> - not future proof -- for example, if a method name gets changed or moved, the code using the method still compiles.
>

Yes, these problems can happen across plugins/host, database design/db apps. Host can't validate its plugins. Host doesn't know what plugins can provide. DB apps which I know don't have much fancy technics to be future proof (what if my db design changes? those SQL won't immediately fail at compile time, only when you run it.)

> If we lose all these things, there must be *something* we gain by doing this, right?
>
> Also, what is the benefit of doing something like this versus specifically calling the dispatcher instead of having the compiler translate it?
>

The benefit is you don't need to write the call function, you don't need to write the string quote. Take a look at my other posts about the usecases of this proposal(ddl, ddbi).

>>
>>> Also, how do you overload the return value?  Using this proposal, you can't have different dynamic methods that return different types.
>>>
>>
>> Umm, maybe make the compiler to pass the return type into the opDot would allow the opDot func to decide which overload func to call.
>
> Walter already has issues overloading on return type, I'm not sure this is any different.
>
> -Steve

Actually different, Walter needs to modify the overload mechanism in the current compiler for different function finger prints. What I need to do is sending the return type to the opDot method. Because the overloading is done by the opDot func at runtime, so I don't have Walter's difficulty in dealing with overloading :D

-- 
使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
April 17, 2009
在 Fri, 17 Apr 2009 23:34:37 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:

> On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl@nospam.org> wrote:
>
>> 在 Fri, 17 Apr 2009 23:20:53 +0800,davidl <davidl@nospam.org> 写道:
>>
>>> 在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:
>>>
>>>> On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax@gmail.com> wrote:
>>>>
>>>>> I don't fully understand the example though. In writefln((v.qq = 5).i),
>>>>> how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate
>>>>> the 5 to the new B()?
>>>>
>>>> I think it translates to
>>>>
>>>> opDotExp("qq") = 5
>>>>
>>>> Without knowing the signature of qq, how is the compiler supposed to infer that it is a property?  In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.
>>>>
>>>> I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges.  It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
>>>>
>>>
>>> Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).
>>>
>>>
>>
>> DDBI can also benefit from it.
>>
>> Consider the use case:
>> myRow.Col1 = "abc";
>
> Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper.
>
> Plus it's not terribly hard to write:
>
> myRow.set("Col1", "abc");
>
> I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.
>
> -Steve

Actually in a lot cases, you don't have the time to write the static wrapper.
Also for a COM object, you don't want to call it in such ways:

comobj.callfunc("ComObjFunc", 3,4,5);

You probably want to call it only by comobj.ComObjFunc(3,4,5);

Yes static wrapper can solve these all. Problem is not in all cases you want to make a static binding for it.


-- 
使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
April 17, 2009
Steven Schveighoffer wrote:
> On Fri, 17 Apr 2009 10:32:04 -0400, Denis Koroskin <2korden@gmail.com> wrote:
> 
>> On Fri, 17 Apr 2009 18:24:04 +0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>>
>>> On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax@gmail.com>
>>> wrote:
>>>
>>>> I don't fully understand the example though. In writefln((v.qq = 5).i),
>>>> how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't
>>>> propagate
>>>> the 5 to the new B()?
>>>
>>> I think it translates to
>>>
>>> opDotExp("qq") = 5
>>>
>>> Without knowing the signature of qq, how is the compiler supposed to
>>> infer that it is a property?  In fact, I think this might be a
>>> limitation of this syntax, you can't define dynamic properties.
>>>
>>> I for one, can't really see a huge benefit, but then again, I don't
>>> normally work with dynamic-type langauges.  It looks to me like a huge
>>> hole that the compiler will ignore bugs that would have been caught if
>>> the methods were strongly typed:
>>>
>>> class c
>>> {
>>>    void opDotExp(char[] methodname,...)
>>>    {
>>>       if(methodname == "mymethod")
>>>          callMyMethod();
>>>       else
>>>          throw new Exception("bad method name: " ~ methodname);
>>>    }
>>> }
>>>
>>> void foo(c myc, bool rarelySetToTrue)
>>> {
>>>    if(rarelySetToTrue)
>>>      myc.mymethud(); // compiles, will throw runtime exception
>>> }
>>>
>>> Also, how do you overload the return value?  Using this proposal, you
>>> can't have different dynamic methods that return different types.
>>>
>>> -Steve
>>
>> Here is how it could be done:
>>
>> class C
>> {
>>     auto opDot(string methodName, T... args)(T args) // opDotExp renamed to opDot
>>     {
>>         static if (methodName == "length") {
>>             return _length; // return type is size_t
>>         } else static if (methodName == "resize") {
>>             _resize(args); // return type is void
>>         }
>>     }
>> }
>>
> 
> Look! I found a way to implement this *in the current compiler*!:
> 
> class C
> {
>    size_t length()
>    {
>       return _length;
>    }
> 
>    void resize(T...)(T args)
>    {
>       _resize(args);
>    }
> }
> 
> sorry, couldn't help myself :P
> 
> -Steve

Yah, glad someone mentioned it :o). The best way is a blend - you can statically dispatch on some popular/heavily-used names, then rely on a hashtable lookup for dynamic stuff.

Andrei
April 17, 2009
Steven Schveighoffer wrote:
> Sure, but what is the reason to need dynamic methods?  I'm just trying to understand the usefulness of it.  If a method is dynamic, we lose the following things:
> 
> - compile-time type/signature checking
> - IDE assistance in determining which methods are available
> - ease of tracing where a method call goes.
> - not future proof -- for example, if a method name gets changed or moved, the code using the method still compiles.
> 
> If we lose all these things, there must be *something* we gain by doing this, right?

There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.

> Also, what is the benefit of doing something like this versus specifically calling the dispatcher instead of having the compiler translate it?

Probably that's more of a "last mile" thing.


Andrei
April 17, 2009
Steven Schveighoffer wrote:
> On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl@nospam.org> wrote:
> 
>> 在 Fri, 17 Apr 2009 23:20:53 +0800,davidl <davidl@nospam.org> 写道:
>>
>>> 在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy@yahoo.com> 写道:
>>>
>>>> On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax@gmail.com> wrote:
>>>>
>>>>> I don't fully understand the example though. In writefln((v.qq = 5).i),
>>>>> how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate
>>>>> the 5 to the new B()?
>>>>
>>>> I think it translates to
>>>>
>>>> opDotExp("qq") = 5
>>>>
>>>> Without knowing the signature of qq, how is the compiler supposed to infer that it is a property?  In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.
>>>>
>>>> I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges.  It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
>>>>
>>>
>>> Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).
>>>
>>>
>>
>> DDBI can also benefit from it.
>>
>> Consider the use case:
>> myRow.Col1 = "abc";
> 
> Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper.
> 
> Plus it's not terribly hard to write:
> 
> myRow.set("Col1", "abc");
> 
> I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.
> 
> -Steve

I believe it is entirely syntax sugar. It's no different to:

foo(char [] funcname, T...) (T args){}

But it allows you to eliminate the foo!("funcname")(args) with funcname(args).  Which is a _very_ significant improvement.

BTW, I think it _must_ be done as a template, as Andrei suggested.
In the original, you have serious problems with delegates, for example, since the function being called has one more parameter (the function name) than it pretends to have.

April 17, 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail@erdani.org> wrote in message news:gsacm8$1gj9$2@digitalmars.com...
>
> There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.
>

Personally, I've always seen that as extremely sloppy and haphazard.


April 17, 2009
"davidl" <davidl@nospam.org> wrote in message news:op.usje9ia3j5j59l@my-tomato...
>
> The benefit is you don't need to write the call function,

...But you do have to write the opDotExp() function. How is that less work than just writing a dispatch function?

> you don't need to write the string quote.

I think I'd prefer that. If I put something in quotes, that tells me that typos might not get detected until runtime. But if I don't use quotes, and it compiles, then I know it's ok. With opDotExp, that certainty goes right out the window. All of a sudden I never know if an identifier following a dot compiled because it's ok, or because the error detection has been deferred. I'd feel like I was working in a dynamic language and I *HATE* working with dynamic languages. It's like trying to construct a building on a patch of ground that you know at any moment could change into a lake, sand, cliffside, or simply cease to exist without any warning.

Additionally, here's an example from Haxe's xml.Fast:

page.node.html.node.head.node.title.x.addChild(Xml.createPCData("Hello"));

Think fast without any close inspection: What's the path being used? Umm...

Ok, without opDotExp, that would be:

page.node("html").node("head").node("title").x.addChild(Xml.createPCData("Hello"));

That's a hell of a lot easier to read. Very easy now to see, at a mere glance, the path is "html/head/title".

Of course, you could adjust the API for the Haxe/opDotExp version to be more like:

page.html.head.title.x.addChild(Xml.createPCData("Hello"));

But now (in addition to still not having the certainty of "if an unquoted identifier compiles, it must be ok"), you've opened yourself up to a world of naming collision issues.


April 17, 2009
Nick Sabalausky:
> > There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.
> 
> Personally, I've always seen that as extremely sloppy and haphazard.

Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python. In Ruby it is more common.
Usually in such languages such things are less dangerous because the code contains lot of tests anyway.
Some people say that a way to remove most of the downsides of monkey patching is to make it scoped, that is the changes (like a method added or replaced) to a class aren't seen globally in the whole program (like from other modules), but only in the scope where such change is done (and its subscopes). I think I have not seen languages where this is doable yet.

Bye,
bearophile
April 17, 2009
Reply to Andrei,
> Cool! I suggest the rewrite:
> 
> c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args)
> 

vote++;

> That way you have the option of handling the method name statically or
> dynamically.
> 
> Andrei
>