www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - shortcut for dynamic dispatch and operators

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
An idea I just had when thinking about how ugly opDispatch and opBinary  
operators will be if we get those was, wouldn't it be cool if the compiler  
could translate:

myTemplateMethod("abc" || "def")() if(condition) {}

to

myTemplateMethod(string __x)() if((__x == "abc" || __x == "def") &&  
condition) {}

It makes dispatch based on compile-time strings much more palatable, for  
example:

opDispatch("foo" || "bar")() {...}
opBinary("+" || "-" || "*")(int rhs) {...}

instead of:

opDispatch(string fn)() if(fn == "foo" || fn == "bar") {...}
opBinary(string op)() if(op == "+" || op == "-" || op == "*")(int rhs)  
{...}

In fact, it can be generalized to any type which has literals:

factorial(int x)(){ return factorial!(x-1)() * x;}
factorial(1)() { return 1;}

What I don't know is if the || works in all cases -- because something  
like true || false is a valid expression.  Maybe someone can come up with  
a better way.

-Steve
Dec 01 2009
next sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Dec 1, 09 22:30, Steven Schveighoffer wrote:
 An idea I just had when thinking about how ugly opDispatch and opBinary
 operators will be if we get those was, wouldn't it be cool if the
 compiler could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x == "abc" || __x == "def") &&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable, for
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn == "foo" || fn == "bar") {...}
 opBinary(string op)() if(op == "+" || op == "-" || op == "*")(int rhs)
 {...}

 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something
 like true || false is a valid expression. Maybe someone can come up with
 a better way.

 -Steve
Alternative suggestion: Make "x in y" returns a bool and works for arrays. Then you can write int opBinary(string s)(int rhs) if (s in ["+", "-", "*", "/", "^", "|", "&"]) { ... }
Dec 01 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
KennyTM~ wrote:
 On Dec 1, 09 22:30, Steven Schveighoffer wrote:
 An idea I just had when thinking about how ugly opDispatch and opBinary
 operators will be if we get those was, wouldn't it be cool if the
 compiler could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x == "abc" || __x == "def") &&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable, for
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn == "foo" || fn == "bar") {...}
 opBinary(string op)() if(op == "+" || op == "-" || op == "*")(int rhs)
 {...}

 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something
 like true || false is a valid expression. Maybe someone can come up with
 a better way.

 -Steve
Alternative suggestion: Make "x in y" returns a bool and works for arrays. Then you can write int opBinary(string s)(int rhs) if (s in ["+", "-", "*", "/", "^", "|", "&"]) { ... }
It's a bit difficult to see a very thin operator mask a linear operation, but I'm thinking maybe "x in y" could be defined if y is a compile-time array. In that case, the compiler knows the operation and the operand so it may decide to change representation as it finds fit. Andrei
Dec 01 2009
next sibling parent reply =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
Andrei Alexandrescu wrote:
 KennyTM~ wrote:
 On Dec 1, 09 22:30, Steven Schveighoffer wrote:
 An idea I just had when thinking about how ugly opDispatch and opBinary
 operators will be if we get those was, wouldn't it be cool if the
 compiler could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x == "abc" || __x == "def") &&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable, for
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn == "foo" || fn == "bar") {...}
 opBinary(string op)() if(op == "+" || op == "-" || op == "*")(int rhs)
 {...}

 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something
 like true || false is a valid expression. Maybe someone can come up with
 a better way.

 -Steve
Alternative suggestion: Make "x in y" returns a bool and works for arrays. Then you can write int opBinary(string s)(int rhs) if (s in ["+", "-", "*", "/", "^", "|", "&"]) { ... }
It's a bit difficult to see a very thin operator mask a linear operation, but I'm thinking maybe "x in y" could be defined if y is a compile-time array. In that case, the compiler knows the operation and the operand so it may decide to change representation as it finds fit. Andrei
What do you suggest using when you need to find out if an object is in an array? Arrays lacking opIn bothers me.
Dec 01 2009
next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 12:15 PM, Pelle M=E5nsson <pelle.mansson gmail.com> =
wrote:
 It's a bit difficult to see a very thin operator mask a linear operation=
,
 but I'm thinking maybe "x in y" could be defined if y is a compile-time
 array. In that case, the compiler knows the operation and the operand so=
it
 may decide to change representation as it finds fit.

 Andrei
What do you suggest using when you need to find out if an object is in an array? Arrays lacking opIn bothers me.
I'm guessing Andrei would recommend std.range.find. --bb
Dec 01 2009
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 12:23 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Tue, Dec 1, 2009 at 12:15 PM, Pelle M=E5nsson <pelle.mansson gmail.com=
 wrote:
 It's a bit difficult to see a very thin operator mask a linear operatio=
n,
 but I'm thinking maybe "x in y" could be defined if y is a compile-time
 array. In that case, the compiler knows the operation and the operand s=
o it
 may decide to change representation as it finds fit.

 Andrei
What do you suggest using when you need to find out if an object is in a=
n
 array? Arrays lacking opIn bothers me.
I'm guessing Andrei would recommend std.range.find.
er... std.algorithm.find, I mean. --bb
Dec 01 2009
parent =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
Bill Baxter wrote:
 On Tue, Dec 1, 2009 at 12:23 PM, Bill Baxter <wbaxter gmail.com> wrote:
 On Tue, Dec 1, 2009 at 12:15 PM, Pelle M�nsson <pelle.mansson gmail.com>
wrote:
 It's a bit difficult to see a very thin operator mask a linear operation,
 but I'm thinking maybe "x in y" could be defined if y is a compile-time
 array. In that case, the compiler knows the operation and the operand so it
 may decide to change representation as it finds fit.

 Andrei
What do you suggest using when you need to find out if an object is in an array? Arrays lacking opIn bothers me.
I'm guessing Andrei would recommend std.range.find.
er... std.algorithm.find, I mean. --bb
I find if (x in [1, 2, 3]) { } more clear than if ([1, 2, 3].find(x).length != 0) { }
Dec 01 2009
prev sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2009-12-01 14:01:26 -0500, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 KennyTM~ wrote:
 Alternative suggestion:
 
 Make "x in y" returns a bool and works for arrays. Then you can write
 
 int opBinary(string s)(int rhs) if (s in ["+", "-", "*", "/", "^", "|", 
 "&"]) { ... }
It's a bit difficult to see a very thin operator mask a linear operation, but I'm thinking maybe "x in y" could be defined if y is a compile-time array. In that case, the compiler knows the operation and the operand so it may decide to change representation as it finds fit.
I don't like making this compile-time only. There are many cases where you may want to do the same check at runtime and it'd be a bother to need a different syntax. Better to create a wrapper struct for such arrays: s in set("+", "-", "*", "/", "^", "|", "&") where set() returns a Set!string struct wrapping a sorted array of those operators for which 'in' could work fast even at runtime. Make sure it works with CTFE and you have what you want. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 01 2009
prev sibling next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 6:30 AM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 An idea I just had when thinking about how ugly opDispatch and opBinary
 operators will be if we get those was, wouldn't it be cool if the compile=
r
 could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x =3D=3D "abc" || __x =3D=3D "def") =
&&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable, for
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn =3D=3D "foo" || fn =3D=3D "bar") {...}
 opBinary(string op)() if(op =3D=3D "+" || op =3D=3D "-" || op =3D=3D "*")=
(int rhs) {...}
 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something li=
ke
 true || false is a valid expression. =A0Maybe someone can come up with a
 better way.
The closest thing is the specialization syntax: factorial(int x : 1)() { return 1;} The main problem with your suggestion is that for most practical uses you actually need to know what the parameter was, not just that it was either "foo" or "bar". So you need to put a symbol somewhere in that signature to bind the actual value to. But I agree, some syntax like opDispatch(x : "foo" || "bar")() { /* use x */ ...} would look much nicer. And it's pretty close to current specialization syntax for values. The type "string" can be auto-deduced from the stuff after the colon. But there are more conditions that you'd like to test than just "||". I guess I'd prefer to just be able to move a whole if clause to after a colon. void opDispatch(fn : fn =3D=3D "foo" || fn =3D=3D "bar")(Variant arg...= ) {} --bb
Dec 01 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 01 Dec 2009 11:24:17 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 On Tue, Dec 1, 2009 at 6:30 AM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 An idea I just had when thinking about how ugly opDispatch and opBinary
 operators will be if we get those was, wouldn't it be cool if the  
 compiler
 could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x == "abc" || __x == "def") &&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable, for
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn == "foo" || fn == "bar") {...}
 opBinary(string op)() if(op == "+" || op == "-" || op == "*")(int rhs)  
 {...}

 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something  
 like
 true || false is a valid expression.  Maybe someone can come up with a
 better way.
The closest thing is the specialization syntax: factorial(int x : 1)() { return 1;} The main problem with your suggestion is that for most practical uses you actually need to know what the parameter was, not just that it was either "foo" or "bar".
Yeah, I thought the __x in my example would have to be some pre-defined symbol, but I realized that if you had multiple such parameters it wouldn't work...
 So you need to put a symbol somewhere in that
 signature to bind the actual value to.

 But I agree, some syntax like
    opDispatch(x : "foo" || "bar")() {  /* use x */ ...}
I like that, that works for me. I'd even like: opDispatch(string x : "foo" || "bar")() {} better than having to do the if clause at the end of the signature.
 would look much nicer.  And it's pretty close to current
 specialization syntax for values.  The type "string" can be
 auto-deduced from the stuff after the colon.  But there are more
 conditions that you'd like to test than just "||".  I guess I'd prefer
 to just be able to move a whole if clause to after a colon.

     void opDispatch(fn : fn == "foo" || fn == "bar")(Variant arg...) {}
You can do the full if clause with the current syntax if you need more complex situations than just matching against a list. I wasn't looking to replace the template contracts, I just think the most common case for opDispatch and opBinary is going to be "if symbol is this or that or the other thing", so it should be easier to use than the template contracts. With your syntax, it's almost an extension of current syntax, so it might be doable (type inference would be a nice bonus). -Steve
Dec 01 2009
parent reply Bill Baxter <wbaxter gmail.com> writes:
On Tue, Dec 1, 2009 at 8:58 AM, Steven Schveighoffer
<schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 11:24:17 -0500, Bill Baxter <wbaxter gmail.com> wrote=
:
 On Tue, Dec 1, 2009 at 6:30 AM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 An idea I just had when thinking about how ugly opDispatch and opBinary
 operators will be if we get those was, wouldn't it be cool if the
 compiler
 could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x =3D=3D "abc" || __x =3D=3D "def"=
) &&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable, fo=
r
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn =3D=3D "foo" || fn =3D=3D "bar") {...}
 opBinary(string op)() if(op =3D=3D "+" || op =3D=3D "-" || op =3D=3D "*=
")(int rhs)
 {...}

 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something
 like
 true || false is a valid expression. =A0Maybe someone can come up with =
a
 better way.
The closest thing is the specialization syntax: =A0 =A0factorial(int x : 1)() { return 1;} The main problem with your suggestion is that for most practical uses you actually need to know what the parameter was, not just that it was either "foo" or "bar".
Yeah, I thought the __x in my example would have to be some pre-defined symbol, but I realized that if you had multiple such parameters it wouldn=
't
 work...

 So you need to put a symbol somewhere in that
 signature to bind the actual value to.

 But I agree, some syntax like
 =A0 opDispatch(x : "foo" || "bar")() { =A0/* use x */ ...}
I like that, that works for me. =A0I'd even like: opDispatch(string x : "foo" || "bar")() {} better than having to do the if clause at the end of the signature.
 would look much nicer. =A0And it's pretty close to current
 specialization syntax for values. =A0The type "string" can be
 auto-deduced from the stuff after the colon. =A0But there are more
 conditions that you'd like to test than just "||". =A0I guess I'd prefer
 to just be able to move a whole if clause to after a colon.

 =A0 =A0void opDispatch(fn : fn =3D=3D "foo" || fn =3D=3D "bar")(Variant =
arg...) {}
 You can do the full if clause with the current syntax if you need more
 complex situations than just matching against a list. =A0I wasn't looking=
to
 replace the template contracts, I just think the most common case for
 opDispatch and opBinary is going to be "if symbol is this or that or the
 other thing", so it should be easier to use than the template contracts.
 =A0With your syntax, it's almost an extension of current syntax, so it mi=
ght
 be doable (type inference would be a nice bonus).
Well with "x in array" syntax you could do void opDispatch(fn : fn in ["foo","bar"])(Variant arg...) {} Part of what annoys me about the if clauses is just that they are separated from the template arguments by the function arguments (or by other template arguments), so I'd like to see a way to put those conditions closer to the parameters they're constraining, regardless of the brevity aspect. In fact something like this would be nice: void aTemplate( fn if(fn in ["foo","bar"]), Args... if (Args.length =3D=3D 2)) (Args x) { ... } --bb
Dec 01 2009
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 01 Dec 2009 12:27:07 -0500, Bill Baxter <wbaxter gmail.com> wrote:

 On Tue, Dec 1, 2009 at 8:58 AM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 On Tue, 01 Dec 2009 11:24:17 -0500, Bill Baxter <wbaxter gmail.com>  
 wrote:

 On Tue, Dec 1, 2009 at 6:30 AM, Steven Schveighoffer
 <schveiguy yahoo.com> wrote:
 An idea I just had when thinking about how ugly opDispatch and  
 opBinary
 operators will be if we get those was, wouldn't it be cool if the
 compiler
 could translate:

 myTemplateMethod("abc" || "def")() if(condition) {}

 to

 myTemplateMethod(string __x)() if((__x == "abc" || __x == "def") &&
 condition) {}

 It makes dispatch based on compile-time strings much more palatable,  
 for
 example:

 opDispatch("foo" || "bar")() {...}
 opBinary("+" || "-" || "*")(int rhs) {...}

 instead of:

 opDispatch(string fn)() if(fn == "foo" || fn == "bar") {...}
 opBinary(string op)() if(op == "+" || op == "-" || op == "*")(int rhs)
 {...}

 In fact, it can be generalized to any type which has literals:

 factorial(int x)(){ return factorial!(x-1)() * x;}
 factorial(1)() { return 1;}

 What I don't know is if the || works in all cases -- because something
 like
 true || false is a valid expression.  Maybe someone can come up with a
 better way.
The closest thing is the specialization syntax: factorial(int x : 1)() { return 1;} The main problem with your suggestion is that for most practical uses you actually need to know what the parameter was, not just that it was either "foo" or "bar".
Yeah, I thought the __x in my example would have to be some pre-defined symbol, but I realized that if you had multiple such parameters it wouldn't work...
 So you need to put a symbol somewhere in that
 signature to bind the actual value to.

 But I agree, some syntax like
   opDispatch(x : "foo" || "bar")() {  /* use x */ ...}
I like that, that works for me. I'd even like: opDispatch(string x : "foo" || "bar")() {} better than having to do the if clause at the end of the signature.
 would look much nicer.  And it's pretty close to current
 specialization syntax for values.  The type "string" can be
 auto-deduced from the stuff after the colon.  But there are more
 conditions that you'd like to test than just "||".  I guess I'd prefer
 to just be able to move a whole if clause to after a colon.

    void opDispatch(fn : fn == "foo" || fn == "bar")(Variant arg...) {}
You can do the full if clause with the current syntax if you need more complex situations than just matching against a list. I wasn't looking to replace the template contracts, I just think the most common case for opDispatch and opBinary is going to be "if symbol is this or that or the other thing", so it should be easier to use than the template contracts. With your syntax, it's almost an extension of current syntax, so it might be doable (type inference would be a nice bonus).
Well with "x in array" syntax you could do void opDispatch(fn : fn in ["foo","bar"])(Variant arg...) {}
That would also work for me. But I prefer not having to repeat the template parameter name. My goal is to have templated operators as straightforward to type out as it is today: opAdd(int rhs) => opBinary(op: "+")(int rhs) This looks like the closest so far that is consistent with current syntax.
 Part of what annoys me about the if clauses is just that they are
 separated from the template arguments by the function arguments (or by
 other template arguments), so I'd like to see a way to put those
 conditions closer to the parameters they're constraining, regardless
 of the brevity aspect.  In fact something like this would be nice:

 void aTemplate(
        fn  if(fn in ["foo","bar"]),
        Args... if (Args.length == 2))
 (Args x)
 {
        ...
 }
Yes, that can be annoying, but you still need the global 'if' in case you want to constrain on multiple arguments. However, it seems like a reasonable optimization to allow placing if statements after a template parameter. It definitely would make for better readability when the if clauses are complex, but it's still a little more clunky than I would like for implementing an individual operator. -Steve
Dec 01 2009
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
KennyTM~:
 Make "x in y" returns a bool and works for arrays.
That's something more useful than the sum of usefulness of opDispatch, opPow and opLength. You use it all the time in code, and in D it's even more useful than in Python because in D a small linear scan can be very fast. To do that in my dlibs I use the function isIn(item, items), where items can be an AA too of course. Bye, bearophile
Dec 01 2009
parent =?UTF-8?B?UGVsbGUgTcOlbnNzb24=?= <pelle.mansson gmail.com> writes:
bearophile wrote:
 KennyTM~:
 Make "x in y" returns a bool and works for arrays.
That's something more useful than the sum of usefulness of opDispatch, opPow and opLength. You use it all the time in code, and in D it's even more useful than in Python because in D a small linear scan can be very fast. To do that in my dlibs I use the function isIn(item, items), where items can be an AA too of course. Bye, bearophile
I somewhat agree. For small arrays I find it very useful, I use it all the time. compare: if (x in [1, 2, 3]) { } if (x == 1 || x == 2 || x == 3) { } I find the first one prettier. :)
Dec 01 2009