www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - dynamic classes and duck typing

reply Walter Bright <newshound1 digitalmars.com> writes:
One thing Java and Python, Ruby, etc., still hold over D is dynamic 
classes, i.e. classes that are only known at runtime, not compile time. 
In D, this:

    s.foo(3);

could be emulated with:

    s.dynamicMethod("foo", 3);

Unfortunately, that makes it impossible to use s with generic code 
(besides looking unappealing). But with a small feature, we can make 
this work:

    struct S
    {
         ...
	T opDynamic(s : string)(args...);
    }

and then s.foo(3), if foo is not a compile time member of s, is 
rewritten as:

    s.opDynamic!("foo")(3);

and opDynamic defers all the nuts-and-bolts of making this work out of 
the language and into the library.

In particular, opDynamic's parameter and return types should all be 
instances of std.variant.

(This has come up in various forms in this n.g. before, but I don't have 
any references handy.)
Nov 27 2009
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic 
 classes, i.e. classes that are only known at runtime, not compile time. 
 In D, this:
 
    s.foo(3);
 
 could be emulated with:
 
    s.dynamicMethod("foo", 3);
 
 Unfortunately, that makes it impossible to use s with generic code 
 (besides looking unappealing). But with a small feature, we can make 
 this work:
 
    struct S
    {
         ...
     T opDynamic(s : string)(args...);
    }
 
 and then s.foo(3), if foo is not a compile time member of s, is 
 rewritten as:
 
    s.opDynamic!("foo")(3);
 
 and opDynamic defers all the nuts-and-bolts of making this work out of 
 the language and into the library.
 
 In particular, opDynamic's parameter and return types should all be 
 instances of std.variant.
 
 (This has come up in various forms in this n.g. before, but I don't have 
 any references handy.)

One of these is the thread "Fully dynamic d by opDotExp overloading". Andrei
Nov 27 2009
prev sibling next sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Sat, 28 Nov 2009 00:30:14 +0100, Walter Bright  
<newshound1 digitalmars.com> wrote:

 One thing Java and Python, Ruby, etc., still hold over D is dynamic  
 classes, i.e. classes that are only known at runtime, not compile time.  
 In D, this:

     s.foo(3);

 could be emulated with:

     s.dynamicMethod("foo", 3);

 Unfortunately, that makes it impossible to use s with generic code  
 (besides looking unappealing). But with a small feature, we can make  
 this work:

     struct S
     {
          ...
 	T opDynamic(s : string)(args...);
     }

 and then s.foo(3), if foo is not a compile time member of s, is  
 rewritten as:

     s.opDynamic!("foo")(3);

 and opDynamic defers all the nuts-and-bolts of making this work out of  
 the language and into the library.

 In particular, opDynamic's parameter and return types should all be  
 instances of std.variant.

 (This has come up in various forms in this n.g. before, but I don't have  
 any references handy.)

davidl implemented this as opDotExp in "Fully dynamic d by opDotExp overloading" (http://www.digitalmars.com/webnews/newsgroups.php?article_id=88145). I'd really like to see this. Is there a reason to allow only std.variant as parameters? I can easily see this being used where the type (or set of possible types) is known at compile time, but one does not want to implement a lot of boilerplate functions. Also, would the generated functions be usable as propertys? -- Simen
Nov 27 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Simen kjaeraas wrote:
 davidl implemented this as opDotExp in "Fully dynamic d by opDotExp 
 overloading"
 (http://www.digitalmars.com/webnews/newsgroups.php?article_id=88145).

Thanks for the ref. On one page linkies: http://www.digitalmars.com/d/archives/digitalmars/D/Fully_dynamic_d_by_opDotExp_overloading_88145.html http://www.digitalmars.com/d/archives/digitalmars/D/Re_Fully_dynamic_d_by_opDotExp_overloading_88270.html
Nov 27 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Walter Bright wrote:
 Simen kjaeraas wrote:
 davidl implemented this as opDotExp in "Fully dynamic d by opDotExp 
 overloading"
 (http://www.digitalmars.com/webnews/newsgroups.php?article_id=88145).

Thanks for the ref. On one page linkies: http://www.digitalmars.com/d/archives/digitalmars/D/Fully_dynamic_d_by_opDotExp_ov rloading_88145.html http://www.digitalmars.com/d/archives/digitalmars/D/Re_Fully_dynamic_d_by_opDotExp_ov rloading_88270.html

And clearly, this idea was proposed before, including the templated version.
Nov 27 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Walter Bright wrote:
 And clearly, this idea was proposed before, including the templated 
 version.

I also see (reading it) that it was pretty thoroughly discussed. I'm convinced we should do it.
Nov 27 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

 One thing Java and Python, Ruby, etc., still hold over D is dynamic 
 classes, i.e. classes that are only known at runtime, not compile time. 

I see, you want a Swiss army knife language :o) Before choosing a design I suggest to look at how both Java and C#4 have done it, few random links about C#4: http://msdn.microsoft.com/en-us/library/dd264736%28VS.100%29.aspx http://blogs.msdn.com/cburrows/archive/2008/10/27/c-dynamic.aspx http://geekswithblogs.net/sdorman/archive/2008/11/16/c-4.0-dynamic-programming.aspx Similar links can be found for the invokedynamic of Java VM. Bye, bearophile
Nov 27 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 I see, you want a Swiss army knife language :o)
 
 Before choosing a design I suggest to look at how both Java and C#4 have done
it, few random links about C#4:
 http://msdn.microsoft.com/en-us/library/dd264736%28VS.100%29.aspx
 http://blogs.msdn.com/cburrows/archive/2008/10/27/c-dynamic.aspx
 http://geekswithblogs.net/sdorman/archive/2008/11/16/c-4.0-dynamic-programming.aspx

I think the D approach is superior, because it offers many more ways of doing things (it's implemented nearly completely as a library feature). C# was forced to do it with a magic type because it doesn't support templates.
Nov 27 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 bearophile wrote:
 I see, you want a Swiss army knife language :o)

 Before choosing a design I suggest to look at how both Java and C#4 have done


 http://msdn.microsoft.com/en-us/library/dd264736%28VS.100%29.aspx
 http://blogs.msdn.com/cburrows/archive/2008/10/27/c-dynamic.aspx


 I think the D approach is superior, because it offers many more ways of
 doing things (it's implemented nearly completely as a library feature).
 C# was forced to do it with a magic type because it doesn't support
 templates.

Sometimes I feel like there should be a law similar to Greenspun's Law for language design: Any sufficiently long-lived language that promises to be "simpler" than C++ and D will grow to contain an ad-hoc, bug-ridden, informally specified, slow implementation of half of C++ and D.
Nov 27 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 Sometimes I feel like there should be a law similar to Greenspun's Law for
 language design:
 
 Any sufficiently long-lived language that promises to be "simpler" than C++
and D
 will grow to contain an ad-hoc, bug-ridden, informally specified, slow
 implementation of half of C++ and D.

The dogged inventiveness of the C++ community never ceases to amaze me. Someone always finds a way to make a library to support some paradigm. Look at all the things Boost does. The problem, though, is the result is often just so strange I'd rather do without. Sometimes, you just need to improve the language to support things better.
Nov 27 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 Sometimes I feel like there should be a law similar to Greenspun's Law for
 language design:

 Any sufficiently long-lived language that promises to be "simpler" than C++
and D
 will grow to contain an ad-hoc, bug-ridden, informally specified, slow
 implementation of half of C++ and D.

Someone always finds a way to make a library to support some paradigm. Look at all the things Boost does. The problem, though, is the result is often just so strange I'd rather do without. Sometimes, you just need to improve the language to support things better.

Right, but sometimes (though certainly not always) it's better to provide a meta-feature that solves a whole bunch of problems (like better templates) and then solve the individual problems at the library level, rather than add a language feature specifically to address each need. One thing D does very well is allow you to do the same kind of metaprogramming solutions you would do in C++, except that the result doesn't suck. For example, std.range implements functional-style lazy evaluation as a library, and does it well. The point is that, if you can't deal with the complexity of having real templates, you better be prepared for the complexity created by not having them. Having never done it before, I really cannot imagine how people get any work done in a language that doesn't have either duck typing or good templates. It's just too rigid. It seems like modern statically typed languages like Java and C# end up adding tons of ad-hoc workarounds for lacking either of these as well-integrated language features. The best/worst example is auto-boxing.
Nov 27 2009
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 Right, but sometimes (though certainly not always) it's better to provide a
 meta-feature that solves a whole bunch of problems (like better templates) and
 then solve the individual problems at the library level, rather than add a
 language feature specifically to address each need.

Yup. The hard part, though, is figuring out what the magic set of seminal features should be.
 One thing D does very well is
 allow you to do the same kind of metaprogramming solutions you would do in C++,
 except that the result doesn't suck.  For example, std.range implements
 functional-style lazy evaluation as a library, and does it well.  The point is
 that, if you can't deal with the complexity of having real templates, you
better
 be prepared for the complexity created by not having them.

Right. A "simple" language pushes the complexity onto the programmer, so he has to write complicated code instead. D programs tend to be dramatically shorter than the equivalent C++ one.
 Having never done it before, I really cannot imagine how people get any work
done
 in a language that doesn't have either duck typing or good templates.  It's
just
 too rigid.  It seems like modern statically typed languages like Java and C#
end
 up adding tons of ad-hoc workarounds for lacking either of these as
 well-integrated language features.  The best/worst example is auto-boxing.

I tried programming in Java. A friend of mine had an unexpected insight. He used Java a lot at a major corporation. He said an IDE was indispensable because with "one click" you could generate a "hundred lines of code". The light bulb came on. Java makes up for its lack of expressiveness by putting that expressiveness into the IDE! In D, you generate that hundred lines of code with templates and mixins.
Nov 27 2009
prev sibling parent div0 <div0 users.sourceforge.net> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

dsimcha wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 Sometimes I feel like there should be a law similar to Greenspun's Law for


Having never done it before, I really cannot imagine how people get any work done in a language that doesn't have either duck typing or good templates. It's just too rigid. It seems like modern statically typed languages like Java and C# end up adding tons of ad-hoc workarounds for lacking either of these as well-integrated language features. The best/worst example is auto-boxing.

Which is why the .NET framework is so bloody huge. If MS hadn't provided that out of the box in the first version, .NET would have been a dead duck. - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iD8DBQFLET3kT9LetA9XoXwRAlROAKCWpHYX+yZ9CJllO2D+n1TkE5YBIQCeJSnQ BJOhQbYK/ur4ugDwcXbCVVI= =JQlY -----END PGP SIGNATURE-----
Nov 28 2009
prev sibling next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Walter Bright wrote:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic 
 classes, i.e. classes that are only known at runtime, not compile time. 
 In D, this:
 
    s.foo(3);
 
 could be emulated with:
 
    s.dynamicMethod("foo", 3);
 
 Unfortunately, that makes it impossible to use s with generic code 
 (besides looking unappealing). But with a small feature, we can make 
 this work:
 
    struct S
    {
         ...
     T opDynamic(s : string)(args...);
    }
 
 and then s.foo(3), if foo is not a compile time member of s, is 
 rewritten as:
 
    s.opDynamic!("foo")(3);
 
 and opDynamic defers all the nuts-and-bolts of making this work out of 
 the language and into the library.
 
 In particular, opDynamic's parameter and return types should all be 
 instances of std.variant.
 
 (This has come up in various forms in this n.g. before, but I don't have 
 any references handy.)

Seems fine, but how will this interact with "alias...this" and opDot? The former seems simple enough: if the "alias...this" field provides the member, use that, otherwise fall back on opDynamic. The latter seems iffy, though. Maybe something like this: // if the return type of opDot provides the member... (auto tmp = s.opDot, tmp ? tmp.foo(3) : s.opDynamic!"foo"(3)) Hmm... ew... but I can't think of anything better off-hand. The "simple" design would probably be for opDynamic's implementation to make the call on whether to forward to opDot's result; aka, push the decision to the programmer. Stick a mixin somewhere for the most basic case (what I showed above) and its no big deal. -- Chris Nicholson-Sauls
Nov 27 2009
parent "Denis Koroskin" <2korden gmail.com> writes:
On Sat, 28 Nov 2009 10:16:33 +0300, Chris Nicholson-Sauls  
<ibisbasenji gmail.com> wrote:

 Walter Bright wrote:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic  
 classes, i.e. classes that are only known at runtime, not compile time.  
 In D, this:
     s.foo(3);
  could be emulated with:
     s.dynamicMethod("foo", 3);
  Unfortunately, that makes it impossible to use s with generic code  
 (besides looking unappealing). But with a small feature, we can make  
 this work:
     struct S
    {
         ...
     T opDynamic(s : string)(args...);
    }
  and then s.foo(3), if foo is not a compile time member of s, is  
 rewritten as:
     s.opDynamic!("foo")(3);
  and opDynamic defers all the nuts-and-bolts of making this work out of  
 the language and into the library.
  In particular, opDynamic's parameter and return types should all be  
 instances of std.variant.
  (This has come up in various forms in this n.g. before, but I don't  
 have any references handy.)

Seems fine, but how will this interact with "alias...this" and opDot? The former seems simple enough: if the "alias...this" field provides the member, use that, otherwise fall back on opDynamic. The latter seems iffy, though. Maybe something like this: // if the return type of opDot provides the member... (auto tmp = s.opDot, tmp ? tmp.foo(3) : s.opDynamic!"foo"(3)) Hmm... ew... but I can't think of anything better off-hand. The "simple" design would probably be for opDynamic's implementation to make the call on whether to forward to opDot's result; aka, push the decision to the programmer. Stick a mixin somewhere for the most basic case (what I showed above) and its no big deal. -- Chris Nicholson-Sauls

I think opDot should be deprecated and eventually removed. Never used it since alias this was introduced. Why would you use it?
Nov 28 2009
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-11-27 18:30:14 -0500, Walter Bright <newshound1 digitalmars.com> said:

 But with a small feature, we can make this work:
 
     struct S
     {
          ...
 	T opDynamic(s : string)(args...);
     }
 
 and then s.foo(3), if foo is not a compile time member of s, is rewritten as:
 
     s.opDynamic!("foo")(3);
 
 and opDynamic defers all the nuts-and-bolts of making this work out of 
 the language and into the library.

Please make sure it can work to implement properties too. The only thing that worries me is that "functions" defined through opDynamic won't be reachable via reflection. There's no way to call "foo" if "foo" is a runtime string; with regular functions you can use compile-time reflection to build a dispatch table, but for those implemented through opDynamic (which are not available through reflection) it won't work. Also, I would name it "opDispatch" instead. I fail to see anything "dymamic" in it... it's a template so it's static isn't it? Of course you can implement dynamic dispatch with this, but that's not a requirement.
 In particular, opDynamic's parameter and return types should all be 
 instances of std.variant.

That seems unnecessary. It's a template, so you should be able to define opDynamic like this: auto opDynamic(s : string, A...)(A args) { return args[0]; } -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Nov 28 2009
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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
Nov 28 2009
next sibling parent reply biozic <dransic free.fr> writes:
Le 29/11/09 00:36, Walter Bright a écrit :
 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

Seems interesting, but for now the error message when no opDispatch template can be instantiated looks confusing when trying to use a class with an opDispatch implemented, and making e.g. a typo error: ============================================= module lib; class Test { string opDispatch(string name)() { static if (name == "foo") return "foo"; } } ============================================= module main; import lib; import std.stdio; void main() { auto test = new Test; writeln(test.foo); // OK writeln(test.fooo); // Error } ============================================= Error is: """ lib.d(5): Error: function lib.Test.opDispatch!("fooo").opDispatch expected to return a value of type string lib.d(9): Error: template instance lib.Test.opDispatch!("fooo") error instantiating """ nicolas
Nov 29 2009
next sibling parent reply biozic <dransic free.fr> writes:
Le 29/11/09 12:14, Simen kjaeraas a écrit :
 That is because your opDispatch is instantiated no matter what the name
 is, but only does something sensible if it's foo. Try this:

 string opDispatch( string name )( ) {
 static if ( name == "foo" ) {
 return "foo";
 } else {
 static assert( false, "Invalid member name." );
 }
 }

Ok but what still looks confusing is that the error is reported on the template code, as for any template instantiation error, while the user could not be aware of being instantiating a template (or should he?). Anyway, this feature is fun to play with.
Nov 29 2009
parent bearophile <bearophileHUGS lycos.com> writes:
biozic:
 Ok but what still looks confusing is that the error is reported on the 
 template code, as for any template instantiation error,

Using the template constraint has to avoid that problem, improving the error message. And Don will probably improve the error messages in the other templates in future. Bye, bearophile
Nov 29 2009
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-11-29 06:14:21 -0500, "Simen kjaeraas" <simen.kjaras gmail.com> said:

 That is because your opDispatch is instantiated no matter what the name
 is, but only does something sensible if it's foo. Try this:
 
 string opDispatch( string name )( ) {
    static if ( name == "foo" ) {
      return "foo";
    } else {
      static assert( false, "Invalid member name." );
    }
 }

Wouldn't this be even better? string opDispatch(string name)() if (name == "foo") { return "foo"; } I haven't tested that it works though. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Nov 29 2009
parent reply biozic <dransic free.fr> writes:
Le 29/11/09 13:16, Michel Fortin a écrit :
 On 2009-11-29 06:14:21 -0500, "Simen kjaeraas" <simen.kjaras gmail.com>
 said:

 That is because your opDispatch is instantiated no matter what the name
 is, but only does something sensible if it's foo. Try this:

 string opDispatch( string name )( ) {
 static if ( name == "foo" ) {
 return "foo";
 } else {
 static assert( false, "Invalid member name." );
 }
 }

Wouldn't this be even better? string opDispatch(string name)() if (name == "foo") { return "foo"; } I haven't tested that it works though.

It doesn't improve the error message, but it works. It's been a long time since I used D: I didn't know this syntax!
Nov 29 2009
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
biozic wrote:

 Le 29/11/09 13:16, Michel Fortin a écrit :
 On 2009-11-29 06:14:21 -0500, "Simen kjaeraas" <simen.kjaras gmail.com>
 said:

 That is because your opDispatch is instantiated no matter what the name
 is, but only does something sensible if it's foo. Try this:

 string opDispatch( string name )( ) {
 static if ( name == "foo" ) {
 return "foo";
 } else {
 static assert( false, "Invalid member name." );
 }
 }

Wouldn't this be even better? string opDispatch(string name)() if (name == "foo") { return "foo"; } I haven't tested that it works though.

It doesn't improve the error message, but it works. It's been a long time since I used D: I didn't know this syntax!

Don has made a patch to improve these kind of error messages in templates, but that will probably come after D2 is finalized (doesn't affect the language). If you want to resolve the symbol at runtime I think you can get a better error message for throwing an exception or assertion. I don't have the svn dmd, so this isn't tested: void opDispatch(string name)(string file = __FILE__, int line = __LINE__) { if ( !dynamicDispatch(name) ) { // line and file are default initialized from the call site: throw new MethodMissingException(name, file, line); } }
Nov 29 2009
parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Denis Koroskin wrote:

 On Sun, 29 Nov 2009 16:02:24 +0300, Lutger <lutger.blijdestijn gmail.com>

 If you want to resolve the symbol at runtime I think you can get a better
 error message for throwing an exception or assertion. I don't have the
 svn
 dmd, so this isn't tested:

 void opDispatch(string name)(string file = __FILE__, int line = __LINE__)
 {
   if ( !dynamicDispatch(name) )
   {
     // line and file are default initialized from the call site:
     throw new MethodMissingException(name, file, line);
   }
 }

IIRC, this trick only works when __FILE__ and __LINE__ are both template arguments.

hey that's right. That means when Walter fixes the current bug with template parameters, good compile time error messages are possible after all.
Nov 29 2009
parent biozic <dransic free.fr> writes:
Le 29/11/09 14:23, Lutger a écrit :
 Denis Koroskin wrote:

 On Sun, 29 Nov 2009 16:02:24 +0300, Lutger<lutger.blijdestijn gmail.com>

 If you want to resolve the symbol at runtime I think you can get a better
 error message for throwing an exception or assertion. I don't have the
 svn
 dmd, so this isn't tested:

 void opDispatch(string name)(string file = __FILE__, int line = __LINE__)
 {
    if ( !dynamicDispatch(name) )
    {
      // line and file are default initialized from the call site:
      throw new MethodMissingException(name, file, line);
    }
 }

IIRC, this trick only works when __FILE__ and __LINE__ are both template arguments.

hey that's right. That means when Walter fixes the current bug with template parameters, good compile time error messages are possible after all.

I tried: ============================================== module main; import std.stdio; import std.string; class Test { string foo(string name)(string file = __FILE__, int line = __LINE__) { return format("Call of Test.foo at %s(%d).", file, line); } string bar(string name, string file = __FILE__, int line = __LINE__)() { return format("Call of Test.bar at %s(%d).", file, line); } } void main() { auto test = new Test; writeln(test.foo!"something"); writeln(test.bar!"something"); } ============================================== and the output is: Call of Test.foo at test.d(21). Call of Test.bar at test.d(12).
Nov 29 2009
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 29 Nov 2009 11:44:56 +0100, biozic <dransic free.fr> wrote:

 Le 29/11/09 00:36, Walter Bright a =C3=A9crit :
 And here it is (called opDispatch, Michel Fortin's suggestion):

 http://www.dsource.org/projects/dmd/changeset?new=3Dtrunk%2Fsrc 268&o=



Seems interesting, but for now the error message when no opDispatch =

 template can be instantiated looks confusing when trying to use a clas=

 with an opDispatch implemented, and making e.g. a typo error:

 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

 module lib;
 class Test
 {
      string opDispatch(string name)()
      {
          static if (name =3D=3D "foo")
              return "foo";
      }
 }
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

 module main;
 import lib;
 import std.stdio;

 void main()
 {
      auto test =3D new Test;
      writeln(test.foo); // OK
      writeln(test.fooo); // Error
 }
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=

 Error is: """
 lib.d(5): Error: function lib.Test.opDispatch!("fooo").opDispatch  =

 expected to return a value of type string
 lib.d(9): Error: template instance lib.Test.opDispatch!("fooo") error =

 instantiating
 """

 nicolas

That is because your opDispatch is instantiated no matter what the name = = is, but only does something sensible if it's foo. Try this: string opDispatch( string name )( ) { static if ( name =3D=3D "foo" ) { return "foo"; } else { static assert( false, "Invalid member name." ); } } -- = Simen
Nov 29 2009
prev sibling next sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
Walter Bright wrote:

 And here it is (called opDispatch, Michel Fortin's suggestion):
 
 

holy duck, that is quick!
Nov 29 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Lutger wrote:
 Walter Bright wrote:
 
 And here it is (called opDispatch, Michel Fortin's suggestion):

holy duck, that is quick!

Unfortunately, things turned out to be not quite so simple. Stay tuned.
Nov 29 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 29 Nov 2009 16:02:24 +0300, Lutger <lutger.blijdestijn gmail.com=
  =

wrote:
 biozic wrote:

 Le 29/11/09 13:16, Michel Fortin a =C3=A9crit :
 On 2009-11-29 06:14:21 -0500, "Simen kjaeraas" <simen.kjaras gmail.c=



 said:

 That is because your opDispatch is instantiated no matter what the =




 name
 is, but only does something sensible if it's foo. Try this:

 string opDispatch( string name )( ) {
 static if ( name =3D=3D "foo" ) {
 return "foo";
 } else {
 static assert( false, "Invalid member name." );
 }
 }

Wouldn't this be even better? string opDispatch(string name)() if (name =3D=3D "foo") { return "foo"; } I haven't tested that it works though.

It doesn't improve the error message, but it works. It's been a long time since I used D: I didn't know this syntax!

Don has made a patch to improve these kind of error messages in =

 templates,
 but that will probably come after D2 is finalized (doesn't affect the
 language).

 If you want to resolve the symbol at runtime I think you can get a bet=

 error message for throwing an exception or assertion. I don't have the=

 svn
 dmd, so this isn't tested:

 void opDispatch(string name)(string file =3D __FILE__, int line =3D __=

 {
   if ( !dynamicDispatch(name) )
   {
     // line and file are default initialized from the call site:
     throw new MethodMissingException(name, file, line);
   }
 }

IIRC, this trick only works when __FILE__ and __LINE__ are both template= = arguments.
Nov 29 2009
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Walter Bright 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 
 

Fixed reported problems with it: http://www.dsource.org/projects/dmd/changeset?old_path=trunk&old=269&new_path=trunk&new=270
Nov 29 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Simen kjaeraas:
 test.d(10): Error: template instance opDispatch!("bar") does not match  
 template declaration opDispatch(string name,T)

For Walter: this quick coding-testing cycle is an huge improvement over the original way DMD was developed. Things can be improved still of course, but this was an important step. Bye, bearophile
Nov 30 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Simen kjaeraas wrote:
 This still does not compile:
 
 struct foo {
     void opDispatch( string name, T )( T value ) {
     }
 }
 
 void main( ) {
     foo f;
     f.bar( 3.14 );
 }
 
 test.d(10): Error: template instance opDispatch!("bar") does not match 
 template
 declaration opDispatch(string name,T)

It works when I try it.
Nov 30 2009
next sibling parent reply =?ISO-8859-1?Q?=c1lvaro_Castro-Castilla?= <alvcastro yahoo.es> writes:
Walter Bright Wrote:

 Simen kjaeraas wrote:
 This still does not compile:
 
 struct foo {
     void opDispatch( string name, T )( T value ) {
     }
 }
 
 void main( ) {
     foo f;
     f.bar( 3.14 );
 }
 
 test.d(10): Error: template instance opDispatch!("bar") does not match 
 template
 declaration opDispatch(string name,T)

It works when I try it.

It does. Shouldn't this work also? struct foo { void opDispatch( string name, T... )( T values ) { } } void main( ) { foo f; f.bar( 3.14 ); } lvaro Castro-Castilla
Nov 30 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
lvaro Castro-Castilla wrote:
 It does. Shouldn't this work also?
 
 struct foo {
     void opDispatch( string name, T... )( T values ) { 
     }   
 }
                                                                               
                                                        
 void main( ) { 
     foo f;
     f.bar( 3.14 );
 }

Declare as: void opDispatch(string name, T...)(T values...) ^^^
Nov 30 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 On Mon, Nov 30, 2009 at 1:00 PM, Walter Bright
    void opDispatch(string name, T...)(T values...)
                                               ^^^

You didn't use to have to do that with variadic templates. Is that also a new change in SVN?

I believe it was always like that.
 Also, is there any chance you could paste the 1-line bug description
 into your SVN commit messages?
 For those of us who don't have the bug database memorized it would
 make it much easier to find relevant commits.
 
 (for instance I was scanning the commit log to see if there were any
 changes related to how variadic templates work, but all one sees is a
 list of commit messages like "bugzilla 3494".  Takes too long to
 figure such things out if you have to plug each number one-by-one into
 bugzilla.)

Probably :-)
Nov 30 2009
parent reply =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 On Mon, Nov 30, 2009 at 1:00 PM, Walter Bright
    void opDispatch(string name, T...)(T values...)
                                               ^^^

You didn't use to have to do that with variadic templates. Is that also a new change in SVN?

I believe it was always like that.

void test1(T...)(T ts) { writeln(ts); //works as expected } void test2(string s, T...)(T ts) { writeln(s); // requires manual specifying of each type writeln(ts); // e.g. test2!("foo", int, int)(1,2) } void test3(string s, T...)(T ts...) { writeln(s); // silently dies when called with writeln(ts); // test3!("foo")(1,2,3,4) in v2.034 }
Nov 30 2009
next sibling parent =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
Simen kjaeraas wrote:
 On Mon, 30 Nov 2009 23:13:23 +0100, Pelle Månsson 
 <pelle.mansson gmail.com> wrote:
 
 Walter Bright wrote:
 Bill Baxter wrote:
 On Mon, Nov 30, 2009 at 1:00 PM, Walter Bright
    void opDispatch(string name, T...)(T values...)
                                               ^^^

You didn't use to have to do that with variadic templates. Is that also a new change in SVN?


void test1(T...)(T ts) { writeln(ts); //works as expected } void test2(string s, T...)(T ts) { writeln(s); // requires manual specifying of each type writeln(ts); // e.g. test2!("foo", int, int)(1,2) } void test3(string s, T...)(T ts...) { writeln(s); // silently dies when called with writeln(ts); // test3!("foo")(1,2,3,4) in v2.034 }

It would seem Walter is right, but only for opDispatch. This compiles fine. If you want compile errors, move the ellipsis around: struct foo { void opDispatch( string name, T... )( T value... ) { } void bar( T... )( T args ) { } } void main( ) { foo f; f.bar( 3 ); f.baz( 3.14 ); }

Nov 30 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Simen kjaeraas wrote:
 It would seem Walter is right, but only for opDispatch. This compiles
 fine. If you want compile errors, move the ellipsis around:

Hmm, looks like there is a problem, but it has nothing to do with opDispatch, as this: void bar(string s, T...)(T args) doesn't work either.
Nov 30 2009
parent reply Alvaro Castro-Castilla <alvcastro yahoo.es> writes:
Walter Bright Wrote:

 Simen kjaeraas wrote:
 It would seem Walter is right, but only for opDispatch. This compiles
 fine. If you want compile errors, move the ellipsis around:

Hmm, looks like there is a problem, but it has nothing to do with opDispatch, as this: void bar(string s, T...)(T args) doesn't work either.

I think this doesn't work as should. This code: struct foo { void opDispatch( string name, T... )( T values... ) { pragma(msg,values); // ...shows "tuple()" writeln(values); // ...shows nothing at runtime foreach(v;values) { // ...idem writeln(v); } } } void main( ) { foo f; f.bar( 3.14, 6.28 ); } Best regards, lvaro Castro-Castilla
Nov 30 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Alvaro Castro-Castilla wrote:
 I think this doesn't work as should. This code:

Yes, you're right. I'll look into fixing it.
Nov 30 2009
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Simen kjaeraas wrote:
 I'm already in love with this feature.

So am I. It seems to be incredibly powerful. Looks to me you can do things like: 1. hook up to COM's IDispatch 2. create 'classes' at runtime 3. add methods to existing classes (monkey patching) that allow such extensions 4. provide an easy way for users to add plugins to an app 5. the already mentioned "swizzler" functions that are generated at runtime based on the name of the function
Nov 30 2009
next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Simen kjaeraas wrote:
 Oh, and another thing: Will we get property syntax for this?
 
 I'd like to use this for shaders, allowing one to refer to
 the shader's own variables directly from D, but currently I am
 limited to function call syntax (unless I'm missing something?)

You can do it, but be careful - you cannot add data members to a class by using templates. You'll have to fake them, by using enums, or a pointer to the actual data, etc.
Nov 30 2009
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:
 So am I. It seems to be incredibly powerful.

Very powerful things can be dangerous too, they can lead to bugs, etc.
 Looks to me you can do things like:

This is stuff that can be written in the D docs to, for example you can add some of those examples in the D2 docs page about operators. Bye, bearophile
Nov 30 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bill Baxter wrote:
 Also how does this interact with property syntax?

Define opDispatch with property.
Nov 30 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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.
Nov 30 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Bill Baxter 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?

 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
 }


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

It's a limitation similar to not having a field and a method share the same name. It avoids a number of awkward questions such as figuring the meaning of &s.x. Andrei
Nov 30 2009
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 Bill Baxter 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?

 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
 }


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

It's a limitation similar to not having a field and a method share the same name. It avoids a number of awkward questions such as figuring the meaning of &s.x.

I agree. While the compiler currently doesn't check for mixing up properties and methods, I intend to make it do so. I can't see any justification for allowing it.
Nov 30 2009
parent reply Max Samukha <spambox d-coding.com> writes:
On Mon, 30 Nov 2009 22:33:40 -0800, Walter Bright
<newshound1 digitalmars.com> wrote:

I agree. While the compiler currently doesn't check for mixing up 
properties and methods, I intend to make it do so. I can't see any 
justification for allowing it.

Bill rightfully mentioned that it would be impossible to dynamically dispatch to both properties and methods even if those properties and methods don't have conflicting names. And that may really be an unfortunate limitation. For example, it would be problematic to implement a generic wrapper for IDispatch: class ComDispatcher { this(IUnknown iUnk) { // query IDispatch and possibly create a member-names-to-id map, etc. } Variant opDispatch(string method, T...)(T args) { // call method (using DISPATCH_METHOD) } property void opDispatch(string property, T)(T arg) { // set property (using DISPATCH_PROPERTYPUT) } property Variant opDispatch(string property)() { // get property (using DISPATCH_PROPERTYGET) } } auto c = new ComDispatcher(iUnk); c.foo(1); // call method c.bar = 1; // set property int a = c.baz; // get property int b = c.qux(); // call method
Dec 01 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Max Samukha wrote:
 On Mon, 30 Nov 2009 22:33:40 -0800, Walter Bright
 <newshound1 digitalmars.com> wrote:
 
 I agree. While the compiler currently doesn't check for mixing up 
 properties and methods, I intend to make it do so. I can't see any 
 justification for allowing it.

Bill rightfully mentioned that it would be impossible to dynamically dispatch to both properties and methods even if those properties and methods don't have conflicting names. And that may really be an unfortunate limitation. For example, it would be problematic to implement a generic wrapper for IDispatch:

Is there any reason not to just make the IDispatch properties have a function interface?
Dec 01 2009
parent Max Samukha <spambox d-coding.com> writes:
On Tue, 01 Dec 2009 03:15:12 -0800, Walter Bright
<newshound1 digitalmars.com> wrote:

Max Samukha wrote:
 On Mon, 30 Nov 2009 22:33:40 -0800, Walter Bright
 <newshound1 digitalmars.com> wrote:
 
 I agree. While the compiler currently doesn't check for mixing up 
 properties and methods, I intend to make it do so. I can't see any 
 justification for allowing it.

Bill rightfully mentioned that it would be impossible to dynamically dispatch to both properties and methods even if those properties and methods don't have conflicting names. And that may really be an unfortunate limitation. For example, it would be problematic to implement a generic wrapper for IDispatch:

Is there any reason not to just make the IDispatch properties have a function interface?

I don't know. It looks like IDispatch::Invoke requires the invokation flag to be explicitly specified. The wrapper can try to determine the flag using IDispatch::GetTypeInfo. However, objects implementing IDispatch are not required to provide any type information. Denis has suggested a convention-based approach (constraint for names starting with "prop_"). It is not great but may work.
Dec 01 2009
prev sibling parent grauzone <none example.net> writes:
Andrei Alexandrescu wrote:
 Bill Baxter 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?

 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
 }


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

It's a limitation similar to not having a field and a method share the same name. It avoids a number of awkward questions such as figuring the meaning of &s.x.

But isn't it the same problem with overloaded functions? Or is this specific issue already solved in D2? (A short look in the language specification revealed nothing; is the unary & operator even documented?)
 Andrei

Dec 01 2009
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Dec 01 2009
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Dec 01 2009
prev sibling parent Don <nospam nospam.com> writes:
retard wrote:
 Tue, 01 Dec 2009 12:40:21 -0500, Steven Schveighoffer wrote:
 
 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.

(not just to any object, but to those that support it): void foo() {} Dynamic d = ..; if (!d.foo) { d.foo = &foo; } d.foo();

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

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

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

Runtime, not so much. But anything decided at compile time can be forwarded to a runtime function.

You don't seem to have any idea what the term 'dynamic' means. From http://en.wikipedia.org/wiki/Dynamic_programming_language “Dynamic programming language is a term used broadly in computer science to describe a class of high-level programming languages that execute at runtime many common behaviors that other languages might perform during compilation, if at all.” From http://en.wikipedia.org/wiki/Dynamic_typing#Dynamic_typing “A programming language is said to be dynamically typed, when the majority of its type checking is performed at run-time as opposed to at compile-time. In dynamic typing, types are associated with values not variables.” The dynamic quite clearly means something that happens at runtime. It's not a compile time feature.

Well, it does seem to be rather novel in a statically typed, compiled language. It blurs the boundary a bit, so it's not quite clear what naming is appropriate. It enables the same syntax which dynamic programming languages use at runtime. I'm not sure that the fact that it occurs at compile-time rather than run-time is important. (Presumably, a dynamic language is permitted to implement functionality at compile time, if it can do so without affecting the semantics).
Dec 02 2009
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Adam D. Ruppe wrote:
 On Mon, Nov 30, 2009 at 02:02:46PM -0800, Walter Bright wrote:
 3. add methods to existing classes (monkey patching) that allow such 
 extensions

I think allowing this in general is a bad idea - the opDispatch should only be implemented on a small number of classes. The reason is simple: a typo in a method name should be a compile time error the vast majority of the time. If opDispatch was implemented all over the place, allowing random runtime extensions, the error is put off until runtime.

Using opDispatch is up to the discretion of the class designer. I doubt it would be used in any but a small minority of classes.
Nov 30 2009
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Walter Bright wrote:
 Simen kjaeraas wrote:
 I'm already in love with this feature.

So am I. It seems to be incredibly powerful. Looks to me you can do things like: 1. hook up to COM's IDispatch 2. create 'classes' at runtime 3. add methods to existing classes (monkey patching) that allow such extensions 4. provide an easy way for users to add plugins to an app 5. the already mentioned "swizzler" functions that are generated at runtime based on the name of the function

Can you show examples of points 2, 3 and 4? I can't see antyhing "dynamic" in this feature. I can't invoke an object's method based on it's name: class Foo { void opDispatch(string name)() { ... } } Foo foo = new Foo(); string something = get_user_input(); foo.opDispatch!(something)(); // no, can't do it foo.something(); // not the same... So where's the magic? I think opDispatch is just another metaprogramming feature, nothing else.
Dec 01 2009
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
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.
Dec 01 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
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?

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. Also: class Foo { ... opDispatch ... } class Bar : Foo { // Let's make Bar understand more things... ... opDispatch ... } 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.
Dec 01 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
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?

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?
Dec 01 2009
next sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
Ary Borenszweig 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?

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.

I mean at compile-time, grrr. Promise, no more talking with myself. :-P
Dec 01 2009
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
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?

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.


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.
Dec 01 2009
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Denis Koroskin wrote:
 On Tue, 01 Dec 2009 15:47:43 +0300, Ary Borenszweig 
 <ary esperanto.org.ar> 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?

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.


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?

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); ---

I believe there will soon be a library type that would allow that.

It's called a template: void yourMagicFunction(T)(T d) { d.foo(); } I can write that and I can always compile my code. I can use that function with any kind of symbol as long as it defines foo, whether it's by definining it explicitly, in it's hierarchy, in an aliased this symbol or in an opDispatch. That's the same concept as any function in Javascript (except that in Javascript if the argument doesn't define foo it's a runtime error and in D it'll be a compile-time error).
Dec 01 2009
parent =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
Bill Baxter wrote:
 2009/12/1 Ary Borenszweig <ary esperanto.org.ar>:
 Denis Koroskin wrote:
 On Tue, 01 Dec 2009 15:47:43 +0300, Ary Borenszweig <ary esperanto.org.ar>
 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?

returns an associated delegate, then call the delegate. The dynamic part will be loading up the associative array at run time.

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.


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?

such method/property. �In ActionScript (and JavaScript, too, I assume), foo.bar is auto-magically rewritten as foo["bar"]. What's fun in that?

--- 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); ---


void yourMagicFunction(T)(T d) { �d.foo(); } I can write that and I can always compile my code. I can use that function with any kind of symbol as long as it defines foo, whether it's by definining it explicitly, in it's hierarchy, in an aliased this symbol or in an opDispatch. That's the same concept as any function in Javascript (except that in Javascript if the argument doesn't define foo it's a runtime error and in D it'll be a compile-time error).

If you define a catch-all opDispatch that forwards to a method that does dynamic lookup, then the error will be a runtime error. --bb

Dec 01 2009
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
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?

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.


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.
Dec 01 2009
next sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
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?

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.


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.
Dec 01 2009
parent George Moss <rolling-stone gathers-no-moss.org> writes:
Lutger wrote:
 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?

returns an associated delegate, then call the delegate. The dynamic part will be loading up the associative array at run time.

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.


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?

such method/property. In ActionScript (and JavaScript, too, I assume), foo.bar is auto-magically rewritten as foo["bar"]. What's fun in that?

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

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.

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.

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?
Dec 01 2009
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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?

returns an associated delegate, then call the delegate. The dynamic part will be loading up the associative array at run time.

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.


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?

such method/property. In ActionScript (and JavaScript, too, I assume), foo.bar is auto-magically rewritten as foo["bar"]. What's fun in that?

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

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.

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
Dec 01 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
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!
Dec 01 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Dec 01 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 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.

I agree and I'm not misunderstanding you. I'm just saying how Variant should work, not opDispatch!
Dec 01 2009
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
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"]()
Dec 01 2009
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
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.
Dec 01 2009
prev sibling parent reply Don <nospam nospam.com> writes:
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.
Dec 01 2009
parent Don <nospam nospam.com> writes:
Bill Baxter wrote:
 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





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.


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

Yeah, it's all about naming. The thing is, the traditional "dynamic" isn't very dynamic. You can't *really* add new functions at run-time. They all exist in the source code, all you're doing is manipulating function pointers, and the dynamic thing is just syntax sugar for that. If you have a language with a built-in compiler or interpreter, it can be truly dynamic, but I don't think that's the normal use of the term.
Dec 02 2009
prev sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
Ary Borenszweig 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?

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?

I take it back! It would be very cool to have something like ruby's dynamic attribute-based finders in D: http://api.rubyonrails.org/classes/ActiveRecord/Base.html
Dec 21 2009
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
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/
Dec 01 2009
prev sibling next sibling parent Max Samukha <spambox d-coding.com> writes:
On Tue, 1 Dec 2009 11:45:14 +0000 (UTC), retard <re tard.com.invalid>
wrote:

 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.

But the feature can be used to implement fully dynamic behavior (provided there is extended RTTI, which is already implementable on top of compiletime introspection using a tweaked compiler). For example, Variant can implement opDispatch to forward calls to the contained object: void foo(Variant o) { o.duckMethod(); } foo(Variant(new class { void duckMethod() {} })); BTW, it is not possible currently to create a Variant from a void pointer to the object and the meta-object of that object because D's meta-objects are lacking necessary information. But that is fixable, I guess.
Dec 01 2009
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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?

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
Dec 01 2009
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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?

returns an associated delegate, then call the delegate. The dynamic part will be loading up the associative array at run time.

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.

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
Dec 01 2009
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
Dec 01 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
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
Dec 01 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
2009/12/1 Ary Borenszweig <ary esperanto.org.ar>:
 Denis Koroskin wrote:
 On Tue, 01 Dec 2009 15:47:43 +0300, Ary Borenszweig <ary esperanto.org.a=


 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) { =A0o.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 arr=







 forwarding statically precalculated dispatching.

=A0Exactly! That's the kind of example I was looking for, thanks.

Actuall, just the first part of the example: void foo(Object o) { =A0 =A0o.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 doe=





 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 =





 you define the magic function that catches all. Can't do that in D be=





 the lookup is done at runtime.

 Basically:

 Dynanic d =3D ...;
 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?

=A0The fun is that you can call d.foo and d.bar() even though there is=




 such method/property.
 =A0In 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) { =A0 d.foo(); } var something =3D 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) { =A0 d.foo(); } auto something =3D fromSomewhere(); yourMagicFunction(something); ---

I believe there will soon be a library type that would allow that.

It's called a template: void yourMagicFunction(T)(T d) { =A0d.foo(); } I can write that and I can always compile my code. I can use that functio=

 with any kind of symbol as long as it defines foo, whether it's by
 definining it explicitly, in it's hierarchy, in an aliased this symbol or=

 an opDispatch. That's the same concept as any function in Javascript (exc=

 that in Javascript if the argument doesn't define foo it's a runtime erro=

 and in D it'll be a compile-time error).

If you define a catch-all opDispatch that forwards to a method that does dynamic lookup, then the error will be a runtime error. --bb
Dec 01 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
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> wro=

 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?

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) { =A0 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.


Actuall, just the first part of the example: void foo(Object o) { =A0 =A0 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 doe=





 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 =3D ...;
 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) { =A0 =A0d.foo(); } var something =3D 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) { =A0 =A0d.foo(); } auto something =3D 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: =A0 =A0d.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 { =A0 =A0void foo() { } } can be refactored to: class Something { =A0 =A0void opDispatch(string name) if (name =3D=3D "foo") {} } without problems on the client side either way. In brief, when you see: var x =3D ...; 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=


 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 c=


 yourself). Do you mean to say this 'except' is the obstacle somehow?

 To say it in code:

 void yourMagicDFunction(T)(T d)
 =A0if ( ImplementsFooOrDispatch!T )
 {
 =A0 d.foo(); // may (or not) be rewritten as d.opDispatch!"foo"
 }

 In javascript I understand it is like this:

 void yourMagicJavascriptFunction(T d)
 {
 =A0 d.foo(); // rewritten as d["foo"]
 }

 But with opDisptach implemented like this it is the same in D:

 class DynamicThing
 {
 =A0 =A0void opDispatch(string name)()
 =A0 =A0{
 =A0 =A0 =A0 =A0auto func =3D this.lookupTable[name]; // looks up 'foo'
 =A0 =A0 =A0 =A0func(); //
 =A0 =A0}
 }

 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 =A0d.foo =3D &someOtherFunction. Instead of d.lookupTable["foo"] =3D &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
Dec 01 2009
prev sibling parent Bill Baxter <wbaxter gmail.com> writes:
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?

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) { =A0 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.


Actuall, just the first part of the example: void foo(Object o) { =A0 =A0 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 =3D ...; 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) { =A0 =A0d.foo(); } var something =3D 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) { =A0 =A0d.foo(); } auto something =3D 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: =A0 =A0d.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 { =A0 =A0void foo() { } } can be refactored to: class Something { =A0 =A0void opDispatch(string name) if (name =3D=3D "foo") {} } without problems on the client side either way. In brief, when you see: var x =3D ...; 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'=

 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 co=

 yourself). Do you mean to say this 'except' is the obstacle somehow?

 To say it in code:

 void yourMagicDFunction(T)(T d)
 =A0if ( ImplementsFooOrDispatch!T )
 {
 =A0 d.foo(); // may (or not) be rewritten as d.opDispatch!"foo"
 }

 In javascript I understand it is like this:

 void yourMagicJavascriptFunction(T d)
 {
 =A0 d.foo(); // rewritten as d["foo"]
 }

 But with opDisptach implemented like this it is the same in D:

 class DynamicThing
 {
 =A0 =A0void opDispatch(string name)()
 =A0 =A0{
 =A0 =A0 =A0 =A0auto func =3D this.lookupTable[name]; // looks up 'foo'
 =A0 =A0 =A0 =A0func(); //
 =A0 =A0}
 }

 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 =3D &someOtherFunction. Instead of d.lookupTable["foo"] =3D &someOtherFunction. But I'm not sure such differences make a big impact on any major class of use cases. --bb
Dec 01 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 02 Dec 2009 02:22:01 -0500, retard <re tard.com.invalid> wrote:


 You don't seem to have any idea what the term 'dynamic' means. From
 http://en.wikipedia.org/wiki/Dynamic_programming_language

I'm sure the first person who suggested C++ templates were a functional language was shown wikipedia (or whatever the equivalent at the time was) as well :) -Steve
Dec 02 2009
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 30 Nov 2009 07:10:41 +0100, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Walter Bright 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

Fixed reported problems with it: http://www.dsource.org/projects/dmd/changeset?old_path=trunk&old=269&new_path=trunk&new=270

This still does not compile: struct foo { void opDispatch( string name, T )( T value ) { } } void main( ) { foo f; f.bar( 3.14 ); } test.d(10): Error: template instance opDispatch!("bar") does not match template declaration opDispatch(string name,T) -- Simen
Nov 30 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Nov 30, 2009 at 1:00 PM, Walter Bright
<newshound1 digitalmars.com> wrote:
 =C1lvaro Castro-Castilla wrote:
 It does. Shouldn't this work also?

 struct foo {
 =A0 =A0void opDispatch( string name, T... )( T values ) { =A0 =A0} =A0 }

 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =


 =A0foo f;
 =A0 =A0f.bar( 3.14 );
 }

Declare as: =A0 =A0void opDispatch(string name, T...)(T values...) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =

You didn't use to have to do that with variadic templates. Is that also a new change in SVN? Also, is there any chance you could paste the 1-line bug description into your SVN commit messages? For those of us who don't have the bug database memorized it would make it much easier to find relevant commits. (for instance I was scanning the commit log to see if there were any changes related to how variadic templates work, but all one sees is a list of commit messages like "bugzilla 3494". Takes too long to figure such things out if you have to plug each number one-by-one into bugzilla.) --bb
Nov 30 2009
prev sibling next sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 30 Nov 2009 19:07:38 +0100, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Simen kjaeraas wrote:
 This still does not compile:
  struct foo {
     void opDispatch( string name, T )( T value ) {
     }
 }
  void main( ) {
     foo f;
     f.bar( 3.14 );
 }
  test.d(10): Error: template instance opDispatch!("bar") does not match  
 template
 declaration opDispatch(string name,T)

It works when I try it.

And here. So what are you complaining about? :p Apparently, my build script was wonky, and didn't update correctly. I'm already in love with this feature. We're gonna have a beautiful life together... -- Simen
Nov 30 2009
next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 30 de noviembre a las 22:33 me escribiste:
 Andrei Alexandrescu wrote:
Bill Baxter 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?

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
}


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

It's a limitation similar to not having a field and a method share the same name. It avoids a number of awkward questions such as figuring the meaning of &s.x.

I agree. While the compiler currently doesn't check for mixing up properties and methods, I intend to make it do so. I can't see any justification for allowing it.

What about: property int opDispatch(string n)() if (n.startsWith("prop_")) { // ... } int opDispatch(string n)() if (n.startsWith("meth_")) { // ... } int i = o.prop_x; int j = o.meth_x(); Should this work? Is not that pretty, but it's a compromise. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Y tuve amores, que fue uno sólo El que me dejó de a pie y me enseñó todo...
Dec 01 2009
prev sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tue, Dec 01, 2009 at 03:55:31PM +0300, Denis Koroskin wrote:
 I believe there will soon be a library type that would allow that.

Here's my first try. I don't have the the new compiler handy and am in a rush, so I'm doing it hacky. With the svn compiler, you should be able to almost run this like you'd expect. Running it prints: Running statically defined: test(10) Running dynamically defined test(0) object.Exception: no such method text My vararg code apparently is broken, but meh. ======== import std.stdio; import std.variant; import std.stdarg; class A { // this is our dynamic class void test(int a) { writefln("Running statically defined: test(%d)", a); } // Just like in javascript... A delegate(...)[string] dynamicFunctions; // Return value tells if we should forward to static methods bool dynamicCall(string name, out A ret, ...) { if(auto fun = name in dynamicFunctions) { ret = (*fun)(_arguments); return true; } return false; } void dynamicBind(string name, A delegate(...) fun) { dynamicFunctions[name] = fun; } A opDispatch(string a)(...) { // If we're assigning a delegate, bind it as a member if(_arguments[0] == typeid(A delegate(...))) { dynamicBind(a, *(cast(A delegate(...)*)(_argptr))); return null; } // If it is in the dynamic list, run that A ret; if(dynamicCall(a, ret, _arguments)) return ret; // If not, we'll look it up in our static table int arg = va_arg!(int)(_argptr); static if(__traits(hasMember, this, a)) { A var; // gah, I wish auto var = fun() worked when fun returns // void. static if(__traits(compiles, var = __traits(getMember, this, a)(arg))) return __traits(getMember, this, a)(arg); else { // Could be improved by trying to construct a // dynamic instance from the return value, // whatever it is __traits(getMember, this, a)(arg); return null; } } else throw new Exception("no such method " ~ a); } } void main() { A a = new A; // no dynamically defined members, so this should call the static a.opDispatch!("test")(10); // dynamically define a member to override the static one a.opDispatch!("test")(delegate A(int num) { writefln("Running dynamically defined test(%d)", num); return null; }); // see what runs a.opDispatch!("test")(20); // should throw method not defined a.opDispatch!("text")(30); } ========= If you have the svn compiler, you should be able to replace those opDispatchs with a.test = 10; and stuff like that. There's one thing though: I think the patch checks static stuff first, then if none of that matches, it forwards to opDispatch. For this to work like in Javascript, it will need a small change. 1) If opDispatch is defined, forward the method do it 2) If this compiles, do nothing more -- assume the opDispatch handled it 3) If not, do a normal static member lookup If opDispatch is not defined for the class, do nothing special - treat it like you normally do in D. The downside is you must either put a static constraint on what your opDispatch does (easy - static assert(0); if you don't handle it) or forward to your static members yourself, but the upside is it lets dynamic method overriding like I do here. I think it would be a net positive. Assuming this doesn't work already, of course. -- Adam D. Ruppe http://arsdnet.net
Dec 01 2009
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 30 Nov 2009 23:02:46 +0100, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Simen kjaeraas wrote:
 I'm already in love with this feature.

So am I. It seems to be incredibly powerful. Looks to me you can do things like: 1. hook up to COM's IDispatch 2. create 'classes' at runtime 3. add methods to existing classes (monkey patching) that allow such extensions 4. provide an easy way for users to add plugins to an app 5. the already mentioned "swizzler" functions that are generated at runtime based on the name of the function

I know, and interfacing with scripting languages just got even awesomer than it already was in D. Oh, and another thing: Will we get property syntax for this? I'd like to use this for shaders, allowing one to refer to the shader's own variables directly from D, but currently I am limited to function call syntax (unless I'm missing something?) -- Simen
Nov 30 2009
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Mon, 30 Nov 2009 23:13:23 +0100, Pelle M=C3=A5nsson  =

<pelle.mansson gmail.com> wrote:

 Walter Bright wrote:
 Bill Baxter wrote:
 On Mon, Nov 30, 2009 at 1:00 PM, Walter Bright
    void opDispatch(string name, T...)(T values...)
                                               ^^^

You didn't use to have to do that with variadic templates. Is that also a new change in SVN?


void test1(T...)(T ts) { writeln(ts); //works as expected } void test2(string s, T...)(T ts) { writeln(s); // requires manual specifying of each type writeln(ts); // e.g. test2!("foo", int, int)(1,2) } void test3(string s, T...)(T ts...) { writeln(s); // silently dies when called with writeln(ts); // test3!("foo")(1,2,3,4) in v2.034 }

It would seem Walter is right, but only for opDispatch. This compiles fine. If you want compile errors, move the ellipsis around: struct foo { void opDispatch( string name, T... )( T value... ) { } = void bar( T... )( T args ) { } } void main( ) { foo f; f.bar( 3 ); f.baz( 3.14 ); } -- = Simen
Nov 30 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 01 Dec 2009 00:00:23 +0300, Walter Bright  =

<newshound1 digitalmars.com> wrote:

 =C3=81lvaro Castro-Castilla wrote:
 It does. Shouldn't this work also?
  struct foo {
     void opDispatch( string name, T... )( T values ) {     }   }
                                                                      =


 void main( ) {     foo f;
     f.bar( 3.14 );
 }

Declare as: void opDispatch(string name, T...)(T values...) ^^^

What? I am using code like =C3=81lvaro posted all the time, whereas your= syntax = doesn't even work (according to my test): void foo(T...)(T values) { } foo(42); Error: template test.foo(T...) does not match any function template = declaration Error: template test.foo(T...) cannot deduce template function from = argument types !()(int) I wonder why it works for opDispatch (if it does, as you say).
Nov 30 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Nov 30, 2009 at 3:38 PM, bearophile <bearophileHUGS lycos.com> wrote:
 Walter Bright:
 So am I. It seems to be incredibly powerful.

Very powerful things can be dangerous too, they can lead to bugs, etc.

I'm a bit concerned about what this does to introspection. With a dynamic language like Python, adding runtime methods does not interfere with your ability to enumerate all the methods supported by an object. With this opDispatch it's no longer possible for the compiler to know what list of methods a class responds to. So unless we add some way for a class to enumerate such things, opDispatch effectively kills any introspecting that requires knowing everything in a class. So that would make things like automatic wrapper generation difficult. And automatic mock classes. Anything else that requires enumerating methods? Also how does this interact with property syntax? --bb
Nov 30 2009
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Mon, Nov 30, 2009 at 02:02:46PM -0800, Walter Bright wrote:
 3. add methods to existing classes (monkey patching) that allow such 
 extensions

I think allowing this in general is a bad idea - the opDispatch should only be implemented on a small number of classes. The reason is simple: a typo in a method name should be a compile time error the vast majority of the time. If opDispatch was implemented all over the place, allowing random runtime extensions, the error is put off until runtime. I'm for having the feature - I just don't think it should be used very often. To add methods to existing classes at compile time, the way I'd love to see it done is: void newMethod(SomeClass myThis...) myThis.whatever...{ } SomeClass a; a.newMethod(); // rewritten as newMethod(a) -- Adam D. Ruppe http://arsdnet.net
Nov 30 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Mon, Nov 30, 2009 at 6:03 PM, Walter Bright
<newshound1 digitalmars.com> wrote:
 Bill Baxter wrote:
 Also how does this interact with property syntax?

Define opDispatch with property.

So we can overload on property-ness? 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 } --bb
Nov 30 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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.
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
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.
Dec 01 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
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.
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
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?

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.


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?
Dec 01 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
Tue, 01 Dec 2009 14:05:16 +0200, Ary Borenszweig 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?

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?

Yep, this would be another cool feature. There aren't that many languages that actually support both dynamic and static types. I guess you would indeed need a new type, something like your Dynamic, to define this behavior. With dynamic types, the opDispatch would be automatically rewritten by the compiler to look up the hash table. This way the types would look syntactically like built-in method calls but would act like e.g. python objects.
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 01 Dec 2009 15:47:43 +0300, Ary Borenszweig <ary esperanto.org.ar>  
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?

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.


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?

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); ---

I believe there will soon be a library type that would allow that.
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 01 Dec 2009 16:08:18 +0300, Ary Borenszweig <ary esperanto.org.ar>  
wrote:

 Denis Koroskin wrote:
 On Tue, 01 Dec 2009 15:47:43 +0300, Ary Borenszweig  
 <ary esperanto.org.ar> 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?

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.


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?

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); ---


It's called a template: void yourMagicFunction(T)(T d) { d.foo(); } I can write that and I can always compile my code. I can use that function with any kind of symbol as long as it defines foo, whether it's by definining it explicitly, in it's hierarchy, in an aliased this symbol or in an opDispatch. That's the same concept as any function in Javascript (except that in Javascript if the argument doesn't define foo it's a runtime error and in D it'll be a compile-time error).

No, I was thinking about a Dynamic class: class Foo { void foo() { ... } } void yourMagicFunction(Dynamic d) { d.foo(); // might throw if there is no such method in an underlying class } yourMagicFunction(new Dynamic(new Foo())); There are a few open issues, though: lack or true reflection and lack of overload by return type. For example, I'd like to do the following: Dynamic d = ...; d.foo = 42.0; int i = d.foo; // returns 42 float f = d.foo; // return 42.f Overload by return type would allow that: RetType opDispatch(RetType, string method, Args...)(Args args) { // ... } But relection is still needed to find out what methods a given object has: class Foo { void foo(float f) { ... } } Object o = new Foo(); Dynamic d = new Dynamic(o); d.foo(-1); // should call o.foo(-1.0); but I see no way to implement it currently
Dec 01 2009
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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)? 2. Can we cover templated operators with opDispatch? I can envision something like this: opDispatch(string s)(int rhs) if(s == "+") {...} I'm still hesitant on operators only being definable through templates, since it makes for very ugly and complex function signatures, regardless of whether they are virtual or not. I would be all for it if you can make shortcuts like: operator("+")(int rhs) hm.. that gives me an idea. new post... -Steve
Dec 01 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
Dec 01 2009
parent reply =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
Steven Schveighoffer wrote:
 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 

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

should be kept separate.
Dec 01 2009
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
Bill Baxter Wrote:

 Good counterpoints to my argument.  So I give up on that line.
 
 Here's another, how do you implement the opBinary_r operators with opDispatch?

Kinda cooky, but what about this: a + b -> b.opDispatch!("r+" )(a) -Steve
Dec 01 2009
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
Bill Baxter Wrote:

 On Tue, Dec 1, 2009 at 4:22 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 Bill Baxter Wrote:

 Good counterpoints to my argument. So I give up on that line.

 Here's another, how do you implement the opBinary_r operators with opDispatch?

Kinda cooky, but what about this: a + b -> b.opDispatch!("r+" )(a)

That's what I had in mind too, so I guess it's not so hard to guess. Really the _r convention is also kooky. We're just more used to that. So this isn't really a strong argument for separating opBinary out of opDispatch.

Another argument for at least keeping opBinary and opBinary_r to be defined by the same function -- commutative operators can be defined once: T opDispatch(string s)(T x) if(s == "+" || s == "r+") { return T(this.val + x.val);}
 
 But that is part of why I was asking about opIn -- if opIn_r's
 spelling remains "opIn_r" then we will have both conventions to deal
 with.  Not so good.  But if that one's changing to opDispatch!"in"
 also, then we'll need opSomething!"rin".  Which is kookier than "r+",
 I think, but at least maintains consistency.
 
 But there is a problem.  It means you can't opDispatch on a method called
"rin".
 So I think there would have to be some non-symbol char in the "r"
 prefix used.  Maybe "r:+", "r:+=", "r:in".  Or just a space -- "r +",
 "r in", ... etc.
 But now it's a notch less intuitive.

opIn is definitely a weird one. Normally, you only want to define the reverse version. Like you said, you can't use "rin" because rin isn't a keyword. I think we can probably come up with a non-symbol representation to denote "Reverse" that's intuitive or at least memorable enough. other ideas to ponder: "op.r" (no need for ..r because opDot doesn't have a reverse version) "op this" denoting that 'this' is on the right hand side -Steve
Dec 01 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
Tue, 01 Dec 2009 15:14:56 +0200, Max Samukha wrote:

 On Tue, 1 Dec 2009 11:45:14 +0000 (UTC), retard <re tard.com.invalid>
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.

But the feature can be used to implement fully dynamic behavior (provided there is extended RTTI, which is already implementable on top of compiletime introspection using a tweaked compiler). For example, Variant can implement opDispatch to forward calls to the contained object: void foo(Variant o) { o.duckMethod(); } foo(Variant(new class { void duckMethod() {} })); BTW, it is not possible currently to create a Variant from a void pointer to the object and the meta-object of that object because D's meta-objects are lacking necessary information. But that is fixable, I guess.

Ok, good to know.
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 01 Dec 2009 16:19:58 +0300, Denis Koroskin <2korden gmail.com>
wrote:

 On Tue, 01 Dec 2009 16:08:18 +0300, Ary Borenszweig  
 <ary esperanto.org.ar> wrote:

 Denis Koroskin wrote:
 On Tue, 01 Dec 2009 15:47:43 +0300, Ary Borenszweig  
 <ary esperanto.org.ar> 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?

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.


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?

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); ---


It's called a template: void yourMagicFunction(T)(T d) { d.foo(); } I can write that and I can always compile my code. I can use that function with any kind of symbol as long as it defines foo, whether it's by definining it explicitly, in it's hierarchy, in an aliased this symbol or in an opDispatch. That's the same concept as any function in Javascript (except that in Javascript if the argument doesn't define foo it's a runtime error and in D it'll be a compile-time error).

No, I was thinking about a Dynamic class: class Foo { void foo() { ... } } void yourMagicFunction(Dynamic d) { d.foo(); // might throw if there is no such method in an underlying class } yourMagicFunction(new Dynamic(new Foo())); There are a few open issues, though: lack or true reflection and lack of overload by return type. For example, I'd like to do the following: Dynamic d = ...; d.foo = 42.0; int i = d.foo; // returns 42 float f = d.foo; // return 42.f Overload by return type would allow that: RetType opDispatch(RetType, string method, Args...)(Args args) { // ... } But relection is still needed to find out what methods a given object has: class Foo { void foo(float f) { ... } } Object o = new Foo(); Dynamic d = new Dynamic(o); d.foo(-1); // should call o.foo(-1.0); but I see no way to implement it currently

On a second thought, overload by return type won't work since I'd like to do the following: Dynamic d = ..; d = 42.5; float f = d; // f = 42.5f; int i = d; // d = 42 And this requires an opImplicitCast(T). For a comparison, C# allows the following (http://msdn.microsoft.com/en-us/library/dd264736(VS.100).aspx): // Any object can be converted to dynamic type implicitly, as shown in the // following examples: dynamic d1 = 7; dynamic d2 = "a string"; dynamic d3 = System.DateTime.Today; dynamic d4 = System.Diagnostics.Process.GetProcesses(); // Conversely, an implicit conversion can be dynamically applied to any // expression of type dynamic: int i = d1; string str = d2; DateTime dt = d3; System.Diagnostics.Process[] procs = d4;
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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

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
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 01 Dec 2009 15:06:27 -0500, Pelle Månsson  
<pelle.mansson gmail.com> wrote:

 Steven Schveighoffer wrote:

  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

should be kept separate.

You could say the same thing about dynamic properties. How come we don't split those out as opProperty? opDispatch can do opBinary, it's a subset. It makes no sense to define opDispatch(string s)() if(s == "+") I agree, but I don't see any reason why opBinary(string s)() would fail to compile... -Steve
Dec 01 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 12:38 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 15:06:27 -0500, Pelle M=E5nsson <pelle.mansson gmail.=

 wrote:

 Steven Schveighoffer wrote:

 =A0Isn't opBinary almost identical to opDispatch? =A0The only differenc=



 see is that opBinary works with operators as the 'symbol' and dispatch =



 with valid symbols. =A0Is it important to distinguish between operators=



 custom dispatch?
 =A0-Steve

opBinary is a binary operator, opDispatch can be anything. I think they should be kept separate.

You could say the same thing about dynamic properties. =A0How come we don=

 split those out as opProperty?

That's because of what Andrei pointed out: &a.b . The compiler can't tell if you want a delegate to the method b, or the address of a property b.
 opDispatch can do opBinary, it's a subset. =A0It makes no sense to define
 opDispatch(string s)() if(s =3D=3D "+") I agree, but I don't see any reas=

 opBinary(string s)() would fail to compile...

I don't get your point. It's the compiler that decides to call opBinary and it's only gonna decide to do so for binary operators. Even if you pretend opBinary can accept any string. --bb
Dec 01 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 1:01 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Tue, Dec 1, 2009 at 12:38 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 15:06:27 -0500, Pelle M=E5nsson <pelle.mansson gmail=


 wrote:

 Steven Schveighoffer wrote:

 =A0Isn't opBinary almost identical to opDispatch? =A0The only differen=




 see is that opBinary works with operators as the 'symbol' and dispatch=




 with valid symbols. =A0Is it important to distinguish between operator=




 custom dispatch?
 =A0-Steve

opBinary is a binary operator, opDispatch can be anything. I think they should be kept separate.

You could say the same thing about dynamic properties. =A0How come we do=


 split those out as opProperty?

That's because of what Andrei pointed out: =A0&a.b . The compiler can't tell if you want a delegate to the method b, or the address of a property b.

... but maybe the syntax for "the function itself" should be distinct from "dereference" anyway. I can't think of any reason the two need to use the same syntax other than that &func was called a "function pointer" back in C. There's no case for "generic code" needing it to be the same syntax as far as I can tell. --bb
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 01 Dec 2009 16:01:41 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 On Tue, Dec 1, 2009 at 12:38 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 15:06:27 -0500, Pelle Månsson  
 <pelle.mansson gmail.com>
 wrote:

 Steven Schveighoffer wrote:

  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

opBinary is a binary operator, opDispatch can be anything. I think they should be kept separate.

You could say the same thing about dynamic properties. How come we don't split those out as opProperty?

That's because of what Andrei pointed out: &a.b . The compiler can't tell if you want a delegate to the method b, or the address of a property b.

Huh?
 opDispatch can do opBinary, it's a subset.  It makes no sense to define
 opDispatch(string s)() if(s == "+") I agree, but I don't see any reason  
 why
 opBinary(string s)() would fail to compile...

I don't get your point. It's the compiler that decides to call opBinary and it's only gonna decide to do so for binary operators. Even if you pretend opBinary can accept any string.

My point is, the set of strings passed by the compiler to opBinary is completely disjoint from the set of strings passed by the compiler to opDispatch. So the only reason to keep them separate is because you want to force people to split their code between operators and methods/properties. There is no technical reason we need to keep them separate or to combine them that I can see. -Steve
Dec 01 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
Tue, 01 Dec 2009 10:39:44 -0800, Andrei Alexandrescu 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?

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?

Well, the most important feature of dynamic types in languages like Python is that you don't need to worry about types anywhere. Even with opDispatch you need to configure parametric types for parameters etc. A python coder wouldn't use D unless you can get rid of all type annotations.
Dec 01 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 1:10 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 16:01:41 -0500, Bill Baxter <wbaxter gmail.com> wrote=

 On Tue, Dec 1, 2009 at 12:38 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 15:06:27 -0500, Pelle M=E5nsson
 <pelle.mansson gmail.com>
 wrote:

 Steven Schveighoffer wrote:

 =A0Isn't opBinary almost identical to opDispatch? =A0The only differe=





 see is that opBinary works with operators as the 'symbol' and dispatc=





 works
 with valid symbols. =A0Is it important to distinguish between operato=





 and
 custom dispatch?
 =A0-Steve

opBinary is a binary operator, opDispatch can be anything. I think the=




 should be kept separate.

You could say the same thing about dynamic properties. =A0How come we d=



 split those out as opProperty?

That's because of what Andrei pointed out: =A0&a.b . The compiler can't tell if you want a delegate to the method b, or the address of a property b.

Huh?

If you have this: struct S { int opProperty(string s)() if(s=3D=3D"b") { ... } int opDispatch(string s)() if(s=3D=3D"b") { ... } } S a; auto x =3D &a.b; which one are you talking about? The property a.b or the method a.b()? That's why you can't split out properties as opProperty. But actually maybe this is no longer true? I'm not sure what the property is going to do to how we refer to a function as a piece of data. Maybe D won't require the & any more. Then &a.b could only refer to the property. So anyway, I think your argument is bad as things currently stand. You asked if opBinary and opDispatch are separate, then why not opProperty. Well, there's an ambiguity if you split off opProperty, that's why not. There isn't any ambiguity in splitting off opBinary.
 opDispatch can do opBinary, it's a subset. =A0It makes no sense to defi=



 opDispatch(string s)() if(s =3D=3D "+") I agree, but I don't see any re=



 why
 opBinary(string s)() would fail to compile...

I don't get your point. =A0It's the compiler that decides to call opBinary and it's only gonna decide to do so for binary operators. Even if you pretend opBinary can accept any string.

My point is, the set of strings passed by the compiler to opBinary is completely disjoint from the set of strings passed by the compiler to opDispatch. =A0So the only reason to keep them separate is because you wa=

 force people to split their code between operators and methods/properties=

 There is no technical reason we need to keep them separate or to combine
 them that I can see.

How about this: given only a catch-all opDispatch which implements dynamic dispatch, the compiler cannot statically determine if operators are really implemented or not. Since the list of operators is always finite, it makes sense to have them in a separate "namespace" of sorts. That way if you implement a catch-all opBinary, you're only saying that you implement all /operators/ not all possible methods. And vice versa, you can specify that you only implement some operators, but still have dynamic dispatch that forwards all named methods. Perhaps, though, there should be a rule where opBinary("+") is tried first, and if not defined then opDispatch("+") could be tried. Not sure if it's worth the mental burden of another rule, though. --bb
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 01 Dec 2009 17:24:30 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 On Tue, Dec 1, 2009 at 1:10 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 16:01:41 -0500, Bill Baxter <wbaxter gmail.com>  
 wrote:

 On Tue, Dec 1, 2009 at 12:38 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 15:06:27 -0500, Pelle Månsson
 <pelle.mansson gmail.com>
 wrote:

 Steven Schveighoffer wrote:

  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

opBinary is a binary operator, opDispatch can be anything. I think they should be kept separate.

You could say the same thing about dynamic properties. How come we don't split those out as opProperty?

That's because of what Andrei pointed out: &a.b . The compiler can't tell if you want a delegate to the method b, or the address of a property b.

Huh?

If you have this: struct S { int opProperty(string s)() if(s=="b") { ... } int opDispatch(string s)() if(s=="b") { ... } } S a; auto x = &a.b; which one are you talking about? The property a.b or the method a.b()? That's why you can't split out properties as opProperty.

This seems like an ambiguity. You cannot define both the property b and the method b.
 But actually maybe this is no longer true?  I'm not sure what the
  property is going to do to how we refer to a function as a piece of
 data.  Maybe D won't require the & any more.  Then &a.b could only
 refer to the property.

 So anyway, I think your argument is bad as things currently stand.
 You asked if opBinary and opDispatch are separate, then why not
 opProperty.  Well, there's an ambiguity if you split off opProperty,
 that's why not.  There isn't any ambiguity in splitting off opBinary.

FTR, I'm not pushing this, just pointing out the inconsistency.
 opDispatch can do opBinary, it's a subset.  It makes no sense to  
 define
 opDispatch(string s)() if(s == "+") I agree, but I don't see any  
 reason
 why
 opBinary(string s)() would fail to compile...

I don't get your point. It's the compiler that decides to call opBinary and it's only gonna decide to do so for binary operators. Even if you pretend opBinary can accept any string.

My point is, the set of strings passed by the compiler to opBinary is completely disjoint from the set of strings passed by the compiler to opDispatch. So the only reason to keep them separate is because you want to force people to split their code between operators and methods/properties. There is no technical reason we need to keep them separate or to combine them that I can see.

How about this: given only a catch-all opDispatch which implements dynamic dispatch, the compiler cannot statically determine if operators are really implemented or not.

Why does it have to? proposed implementation: compiler sees 'a + b' compiler rewrites 'a.opBinary!"+"(b)' does it compile? If yes, then a implements the operator. With opDispatch: compiler sees 'a + b' compiler rewrites 'a.opDispatch!"+"(b)' does it compile? If yes, then a implements the operator. I don't see the problem.
 Since the list of operators
 is always finite, it makes sense to have them in a separate
 "namespace" of sorts.   That way if you implement a catch-all
 opBinary, you're only saying that you implement all /operators/ not
 all possible methods.  And vice versa, you can specify that you only
 implement some operators, but still have dynamic dispatch that
 forwards all named methods.

opDispatch(string s, T)(T arg) if(isOperator(s)) opDispatch(string s, T...)(T arg) if(isSymbol(s)) BTW, you are already going to want to do that for both to prevent abuse, see my original reply in this sub-thread. -Steve
Dec 01 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Wed, 02 Dec 2009 00:01:41 +0300, Bill Baxter <wbaxter gmail.com> wrot=
e:

 On Tue, Dec 1, 2009 at 12:38 PM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 15:06:27 -0500, Pelle M=C3=A5nsson  =


 <pelle.mansson gmail.com>
 wrote:

 Steven Schveighoffer wrote:

  Isn't opBinary almost identical to opDispatch?  The only differenc=




 see is that opBinary works with operators as the 'symbol' and  =




 dispatch works
 with valid symbols.  Is it important to distinguish between operato=




 and
 custom dispatch?
  -Steve

opBinary is a binary operator, opDispatch can be anything. I think t=



 should be kept separate.

You could say the same thing about dynamic properties. How come we =


 don't
 split those out as opProperty?

That's because of what Andrei pointed out: &a.b . The compiler can't tell if you want a delegate to the method b, or the=

 address of a property b.

Technically, you are wrong. There is the same ambiguity without function= = overloads: void foo(int a); void foo(float a); auto dg =3D &foo; // which one of the two overloads is chosen and why? Resolving properties is much easier: property and function names can't = overlap, i.e. you can't have property *and* any function with the same = name.
Dec 02 2009
prev sibling next sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 27 de noviembre a las 15:30 me escribiste:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic
 classes, i.e. classes that are only known at runtime, not compile
 time. In D, this:

I like the feature, but I don't understand where is the duck-typing in all this. I think you're confusing duck-typing with dynamic-typing or I'm missing something? -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Ambition makes you look pretty ugly
Nov 29 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Leandro Lucarella wrote:
 Walter Bright, el 27 de noviembre a las 15:30 me escribiste:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic
 classes, i.e. classes that are only known at runtime, not compile
 time. In D, this:

I like the feature, but I don't understand where is the duck-typing in all this. I think you're confusing duck-typing with dynamic-typing or I'm missing something?

Perhaps I am using the term wrong, but I figure it's duck-typing if you can go ahead and try to access methods of an object, and they are checked at runtime and throw some kind of method-not-found exception if they aren't there. With this, it should be possible to construct a type at runtime, and have it work with statically compiled code. This should work very nicely to implement a plug in architecture.
Nov 29 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
Sun, 29 Nov 2009 14:59:27 -0300, Leandro Lucarella wrote:

 Walter Bright, el 27 de noviembre a las 15:30 me escribiste:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic
 classes, i.e. classes that are only known at runtime, not compile time.
 In D, this:

I like the feature, but I don't understand where is the duck-typing in all this. I think you're confusing duck-typing with dynamic-typing or I'm missing something?

Well it seems like the duck typing happens all on compile time with the new feature. You get some of the features of true dynamic languages, but not all. You can't really write python/ruby style dynamic code with it, e.g. class foo { void sayHello() { print("hello"); } } auto bar = new foo(); try { bar.sayBye(); } catch(MethodNotFoundException e) { ... } auto bye_routine(Object o) { return o.sayBye(); } bar.sayBye = { bar.sayHello(); return "and bye"; } println(bye_routine(bar)); Of course this is inefficient and error prone but that's what's it all about in dynamic languages. You get tons of flexibility.
Nov 29 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 29 de noviembre a las 13:52 me escribiste:
 Leandro Lucarella wrote:
Walter Bright, el 27 de noviembre a las 15:30 me escribiste:
One thing Java and Python, Ruby, etc., still hold over D is dynamic
classes, i.e. classes that are only known at runtime, not compile
time. In D, this:

I like the feature, but I don't understand where is the duck-typing in all this. I think you're confusing duck-typing with dynamic-typing or I'm missing something?

Perhaps I am using the term wrong, but I figure it's duck-typing if you can go ahead and try to access methods of an object, and they are checked at runtime and throw some kind of method-not-found exception if they aren't there.

OK, now I see what you mean. Perhaps it would be helpful to have a standard exception for unexistent methods to support that idiom. If we don't every library will create one and it would be a mess. A standard way to test if a method exists would be nice too, something like Python's getattr(), setattr() and hasattr() can be a start. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Demasiado lento para una estrella fugaz Demasiado limpio para lo que vos acostumbras Demasiado claro para tanta oscuridad Demasiados sueños, poca realidad
Nov 29 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
retard, el 29 de noviembre a las 18:27 me escribiste:
 Sun, 29 Nov 2009 14:59:27 -0300, Leandro Lucarella wrote:
 
 Walter Bright, el 27 de noviembre a las 15:30 me escribiste:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic
 classes, i.e. classes that are only known at runtime, not compile time.
 In D, this:

I like the feature, but I don't understand where is the duck-typing in all this. I think you're confusing duck-typing with dynamic-typing or I'm missing something?

Well it seems like the duck typing happens all on compile time with the new feature. You get some of the features of true dynamic languages, but not all. You can't really write python/ruby style dynamic code with it, e.g. class foo { void sayHello() { print("hello"); } } auto bar = new foo(); try { bar.sayBye(); } catch(MethodNotFoundException e) { ... } auto bye_routine(Object o) { return o.sayBye(); } bar.sayBye = { bar.sayHello(); return "and bye"; }

I guess this is a proposed syntax or something right? I guess you're omitting the opDispatch() implementation on purpose. Is property syntax really allowed to assign a new method?
 println(bye_routine(bar));
 
 Of course this is inefficient and error prone but that's what's it all 
 about in dynamic languages. You get tons of flexibility.

I see. As I said in the reply to Walter, I think we need more support if we really want to make dynamic typing (and duck-typing) pleasant in D. As I said, there should be a better way to ask if an object have some methond than trying to use it and catch an exception (like Python's hasattr()). It would be very nice to be able to add methods (and properties!) dynamically to an object too, this is very common in dynamic languages. I know all this can be done, but I think we need an standard facility to avoid everybody implementing its own dynamic typing "framework", which would be a mess to use and hard to interoperate between different implementations. It doesn't have to be a language feature though, if it can be implemented in Phobos. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Una mujer en bicicleta, con sombrero de paja, es la más flagrante violación a las leyes de la aerodinamia. -- Ricardo Vaporeso. 21 de Septiembre de 1917.
Nov 29 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Bill Baxter, el 30 de noviembre a las 16:09 me escribiste:
 On Mon, Nov 30, 2009 at 3:38 PM, bearophile <bearophileHUGS lycos.com> wrote:
 Walter Bright:
 So am I. It seems to be incredibly powerful.

Very powerful things can be dangerous too, they can lead to bugs, etc.

I'm a bit concerned about what this does to introspection. With a dynamic language like Python, adding runtime methods does not interfere with your ability to enumerate all the methods supported by an object. With this opDispatch it's no longer possible for the compiler to know what list of methods a class responds to.

That's another reason to have a better support for dynamic types, even when implemented in the library. Maybe a mixin can be provided to enable some basic functionality, that's common to all objects using opDispatch(), like enumerating the runtime members or checking if a member exist. Anyway, this problem is present in dynamic languages too, for example if you use the __setattr__(), __getattr__() and __hasattr__() magic methods in Python, you can't use introspection to see what's in the object, you have to know its internals to get that information. There are two levels of dynamicity (at least in Python), you can add real members to an object (which can be inspected using the standard Python facilities) or you can use those magic methods (which kills the introspection too). The problem with D (using opDispatch()) is you can't add real members, you can only use magic method to add members at runtime. And that's why I think it would be nice to have some standard facilities to do this extra work, otherwise every D programmer will come up with its own implementation and interoperability will be a nightmare. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Ah, se va en 1981? Pero por qué? ... Ah, porque ya había sido determinado, entonces quiere decir que pronto vamos a elegir presidente nuevo nosot... Ah, nosotros no? Ah, lo van a elegir en la ... Ah! Quiere que le diga? Muy bien pensado, porque cada vez que lo elegimos nosotros no duran nada! -- Tato vs. Tato (1980, Gobierno de Videla)
Nov 30 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
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()
 {
 =A0 =A0S =A0s;
 =A0 =A0writefln("%s", s.x); // writes 1.0
 =A0 =A0writefln("%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. --bb
Nov 30 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Tue, 01 Dec 2009 09:33:40 +0300, Walter Bright  
<newshound1 digitalmars.com> wrote:

 Andrei Alexandrescu wrote:
 Bill Baxter 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?

 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
 }


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

same name. It avoids a number of awkward questions such as figuring the meaning of &s.x.

I agree. While the compiler currently doesn't check for mixing up properties and methods, I intend to make it do so. I can't see any justification for allowing it.

Monkey-patching relies on it: int bar() { return 42; } Dynamic dynamic = new Dynamic(); dynamic.newMethod = &bar; // setter, property version called auto dg = dynamic.newMethod; // getter, property version called auto result = dynamic.newMethod(); // non- property version called
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Dec 01 2009
prev sibling next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
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.
Dec 01 2009
parent BCS <none anon.com> writes:
Hello Denis,

 What if you don't know argument names a-priori? Consider a generic
 Dynamic  class that has nothing but a single opDispatch method.
 

you can do whatever logic you want, even (I think) aliasing the function template opDispatch(string s) { static if(WhateverLogicYouNeed!(s)) alias Something!(s) opDispatch; else alias SomethingElse!(s) opDispatch; }
Dec 02 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
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(): }
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
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();
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Dec 01 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
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.
Dec 01 2009
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
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
Dec 01 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 3:01 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 How about this: given only a catch-all opDispatch which implements
 dynamic dispatch, the compiler cannot statically determine if
 operators are really implemented or not.

Why does it have to? proposed implementation: compiler sees 'a + b' compiler rewrites 'a.opBinary!"+"(b)' does it compile? =A0If yes, then a implements the operator. With opDispatch: compiler sees 'a + b' compiler rewrites 'a.opDispatch!"+"(b)' does it compile? =A0If yes, then a implements the operator. I don't see the problem.
 Since the list of operators
 is always finite, it makes sense to have them in a separate
 "namespace" of sorts. =A0 That way if you implement a catch-all
 opBinary, you're only saying that you implement all /operators/ not
 all possible methods. =A0And vice versa, you can specify that you only
 implement some operators, but still have dynamic dispatch that
 forwards all named methods.

opDispatch(string s, T)(T arg) if(isOperator(s)) opDispatch(string s, T...)(T arg) if(isSymbol(s))

Good counterpoints to my argument. So I give up on that line. Here's another, how do you implement the opBinary_r operators with opDispat= ch? --bb
Dec 01 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 4:22 PM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 Bill Baxter Wrote:

 Good counterpoints to my argument. =A0So I give up on that line.

 Here's another, how do you implement the opBinary_r operators with opDis=


 Kinda cooky, but what about this:

 a + b -> b.opDispatch!("r+" )(a)

That's what I had in mind too, so I guess it's not so hard to guess. Really the _r convention is also kooky. We're just more used to that. So this isn't really a strong argument for separating opBinary out of opDispatch. But that is part of why I was asking about opIn -- if opIn_r's spelling remains "opIn_r" then we will have both conventions to deal with. Not so good. But if that one's changing to opDispatch!"in" also, then we'll need opSomething!"rin". Which is kookier than "r+", I think, but at least maintains consistency. But there is a problem. It means you can't opDispatch on a method called "= rin". So I think there would have to be some non-symbol char in the "r" prefix used. Maybe "r:+", "r:+=3D", "r:in". Or just a space -- "r +", "r in", ... etc. But now it's a notch less intuitive. --bb
Dec 01 2009
prev sibling next sibling parent retard <re tard.com.invalid> writes:
Tue, 01 Dec 2009 12:40:21 -0500, Steven Schveighoffer wrote:

 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.

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

You don't seem to have any idea what the term 'dynamic' means. From http://en.wikipedia.org/wiki/Dynamic_programming_language “Dynamic programming language is a term used broadly in computer science to describe a class of high-level programming languages that execute at runtime many common behaviors that other languages might perform during compilation, if at all.” From http://en.wikipedia.org/wiki/Dynamic_typing#Dynamic_typing “A programming language is said to be dynamically typed, when the majority of its type checking is performed at run-time as opposed to at compile-time. In dynamic typing, types are associated with values not variables.” The dynamic quite clearly means something that happens at runtime. It's not a compile time feature.
Dec 01 2009
prev sibling parent BLS <windevguy hotmail.de> writes:
On 28/11/2009 00:30, Walter Bright wrote:
 One thing Java and Python, Ruby, etc., still hold over D is dynamic
 classes, i.e. classes that are only known at runtime, not compile time.
 In D, this:

 s.foo(3);

Should opDispatch also enable dynamic property injection ? I just thought that it would be nice to have a new __traits() thingy for properties. would make perfectly sense f.i. GUI widgets. Guess I like dispatching but not dymamic injection of properties. which leads me to this question : Will there be support in traits for properties ? Thanks for ignoring my ignorance once again.
Dec 01 2009