digitalmars.D - even more delegate sugar
- Tom S (20/20) Aug 21 2006 While we're at it, how about allowing the construct:
- Don Clugston (19/47) Aug 22 2006 Sounds nice, but nowhere near enough visual cues.
- Oskar Linde (13/69) Aug 22 2006 Would they? (assuming there is no dotimes overload with only one
- Don Clugston (12/75) Aug 22 2006 I was not making that assumption. There's also:
- Oskar Linde (9/73) Aug 22 2006 The fact that C has had this very same issue with if, while, for, et.al....
- Tom S (56/131) Aug 22 2006 I think the proposed syntax should only be allowed only when the
- Don Clugston (16/82) Aug 22 2006 Touché. I forgot about that.
- Tom S (14/23) Aug 22 2006 Umm, nope...
- Don Clugston (5/34) Aug 22 2006 That's exactly what I meant. You can't use 'break' inside opApply, but
- Ivan Senji (14/70) Aug 22 2006 And if we could name arguments at call site then a function:
- Walter Bright (7/35) Aug 22 2006 It is a good idea and I've bandied it around before, and it has its
While we're at it, how about allowing the construct: methodName (arg, arg, ..., arg, { ... }); to be equivalent to: methodName (arg, arg, ..., arg) { ... } and methodName ({ ... }); to methodName {} Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time. -- Tomasz Stachowiak
Aug 21 2006
Tom S wrote:While we're at it, how about allowing the construct: methodName (arg, arg, ..., arg, { ... }); to be equivalent to: methodName (arg, arg, ..., arg) { ... } and methodName ({ ... }); to methodName {} Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code. But an amazing feature of your proposal is that you could write a function void If(bool b, void delegate (void) f); and then write If( cond) { writef(xxxx); } which would behave just like the built-in 'if' statement (albeit without an 'else' clause). Interesting.
Aug 22 2006
Don Clugston wrote:Tom S wrote:Just as I and others have suggested already. I really like it.While we're at it, how about allowing the construct: methodName (arg, arg, ..., arg, { ... }); to be equivalent to: methodName (arg, arg, ..., arg) { ... } and methodName ({ ... }); to methodName {}Would they? (assuming there is no dotimes overload with only one argument) As I understand Toms suggestion, braces would be required when using this syntax. And if not, there is no reason allowing ; to be an empty expression in this case, just like if(10); { writef(x++); } isn't allowed in D today. The error message is: "use '{ }' for an empty statement, not a ';'"Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code.But an amazing feature of your proposal is that you could write a function void If(bool b, void delegate (void) f); and then write If( cond) { writef(xxxx); } which would behave just like the built-in 'if' statement (albeit without an 'else' clause). Interesting.Indeed. /Oskar
Aug 22 2006
Oskar Linde wrote:Don Clugston wrote:I was not making that assumption. There's also: dotimes(int x, void delegate(void) y = { writefln("Surprise"); }); (I think that providing a default values for any such trailing delegate would always create this situation). I don't know if this would be a big problem in practice - but it makes me a bit nervous. What would you do with methodName (int, void delegate(void) ... ) ?Tom S wrote:Just as I and others have suggested already. I really like it.While we're at it, how about allowing the construct: methodName (arg, arg, ..., arg, { ... }); to be equivalent to: methodName (arg, arg, ..., arg) { ... } and methodName ({ ... }); to methodName {}Would they? (assuming there is no dotimes overload with only one argument)Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code.On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.But an amazing feature of your proposal is that you could write a function void If(bool b, void delegate (void) f); and then write If( cond) { writef(xxxx); } which would behave just like the built-in 'if' statement (albeit without an 'else' clause). Interesting.Indeed.
Aug 22 2006
Don Clugston wrote:Oskar Linde wrote:You are correct, of course.Don Clugston wrote:I was not making that assumption. There's also: dotimes(int x, void delegate(void) y = { writefln("Surprise"); }); (I think that providing a default values for any such trailing delegate would always create this situation).Tom S wrote:Would they? (assuming there is no dotimes overload with only one argument)Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code.I don't know if this would be a big problem in practice - but it makes me a bit nervous.The fact that C has had this very same issue with if, while, for, et.al. for centuries should work in favor of the proposal though.What would you do with methodName (int, void delegate(void) ... ) ?Yes, that is an interesting case. One could either: a) live with the ; changing the meaning of the code b) forbid the proposed syntax in the cases where a ; would change the meaning of the code.break would pose a problem though.On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.But an amazing feature of your proposal is that you could write a function void If(bool b, void delegate (void) f); and then write If( cond) { writef(xxxx); } which would behave just like the built-in 'if' statement (albeit without an 'else' clause). Interesting.Indeed.
Aug 22 2006
Oskar Linde wrote:Don Clugston wrote:I think the proposed syntax should only be allowed only when the delegate param doesn't have a default value. Even if only for the sake of clarity.Oskar Linde wrote:You are correct, of course.Don Clugston wrote:I was not making that assumption. There's also: dotimes(int x, void delegate(void) y = { writefln("Surprise"); }); (I think that providing a default values for any such trailing delegate would always create this situation).Tom S wrote:Would they? (assuming there is no dotimes overload with only one argument)Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code.I'm not sure what you mean with the ... there, but if you mean methodName(arg, arg, ..., arg, {}, arg, ..., arg) then perhaps it should not be allowed to use the shorthand. But more on that later.I don't know if this would be a big problem in practice - but it makes me a bit nervous.The fact that C has had this very same issue with if, while, for, et.al. for centuries should work in favor of the proposal though.What would you do with methodName (int, void delegate(void) ... )Yes, that is an interesting case. One could either: a) live with the ; changing the meaning of the code b) forbid the proposed syntax in the cases where a ; would change the meaning of the code.I'd opt for b)Right, but it's not always needed :) Anyway, it's not the only option to go for. For instance, if the semicolon wasn't implicit, one might try some more twists, e.g.: myIf (cond) { } .myElif (cond) { } .myElse (cond) { }; Or the construct methodName([arg, ..., arg, {}], ..., [arg, ..., arg, {}]) could be allowed to expand to methodName(arg, ..., arg) { } ... (arg, ..., arg) { }; or, as Ivan Senji suggested, named args could make it become methodName(arg, ..., arg) { } namedDg = { } ... namedDg = { }; I can immediately imagine writing code like: glPushMatrix { glTranslatef(...); glBegin(GL_TRIANGLES) { glVertex(...); ... glVertex(...); } } Note that this code would also be possible in a similar form: glPushMatrix = { glTranslatef(...); glBegin(GL_TRIANGLES) = { glVertex(...); ... glVertex(...); }; }; ... just if opAssign worked for structs. /* Yet it would be noticeably harder to implement */ -- Tomasz Stachowiakbreak would pose a problem though.On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.But an amazing feature of your proposal is that you could write a function void If(bool b, void delegate (void) f); and then write If( cond) { writef(xxxx); } which would behave just like the built-in 'if' statement (albeit without an 'else' clause). Interesting.Indeed.
Aug 22 2006
Oskar Linde wrote:Don Clugston wrote:Oskar Linde wrote:You are correct, of course.Don Clugston wrote:I was not making that assumption. There's also: dotimes(int x, void delegate(void) y = { writefln("Surprise"); }); (I think that providing a default values for any such trailing delegate would always create this situation).Tom S wrote:Would they? (assuming there is no dotimes overload with only one argument)Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code.I don't know if this would be a big problem in practice - but it makes me a bit nervous.The fact that C has had this very same issue with if, while, for, et.al. for centuries should work in favor of the proposal though.Don Clugston wrote:Oskar Linde wrote:Umm, nope... http://digitalmars.com/d/statement.html#foreach Look at the opApply example. The delegate implementing foreach's body returns != 0 in case of a break. It can be emulated thru e.g. return BREAK; or return CONTINUE; but if there was a way to define a function like: outer.return myBreak() { outer.return BREAK; } ... then things could get even more bizarre ;)Don Clugston wrote:You're right. Although foreach with opApply has the same problem.On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.break would pose a problem though.Aug 22 2006Tom S wrote:Don Clugston wrote:That's exactly what I meant. You can't use 'break' inside opApply, but of course it can be emulated, and the same solution could apply to Foreach function. It's just lacking in syntactic sugar (and probably in performance, too).Oskar Linde wrote:Umm, nope... http://digitalmars.com/d/statement.html#foreach Look at the opApply example. The delegate implementing foreach's body returns != 0 in case of a break.Don Clugston wrote:You're right. Although foreach with opApply has the same problem.On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.break would pose a problem though.It can be emulated thru e.g. return BREAK; or return CONTINUE;but if there was a way to define a function like: outer.return myBreak() { outer.return BREAK; } ... then things could get even more bizarre ;)Aug 22 2006Don Clugston wrote:Tom S wrote:And if we could name arguments at call site then a function: void If(bool c, void delegate (void) Then, void delegate (void) Else = null); could be called like this: If(cond) Then = { writef(xxxx); } Else = { writef(xxxxx); } ;) Wouldn't that be cool? :PWhile we're at it, how about allowing the construct: methodName (arg, arg, ..., arg, { ... }); to be equivalent to: methodName (arg, arg, ..., arg) { ... } and methodName ({ ... }); to methodName {} Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.Sounds nice, but nowhere near enough visual cues. If you leave off a semicolon, the meaning completely changes. dotimes(10); { writef(x++); } and dotimes(10) { writef(x++); } would both be valid code. But an amazing feature of your proposal is that you could write a function void If(bool b, void delegate (void) f); and then write If( cond) { writef(xxxx); } which would behave just like the built-in 'if' statement (albeit without an 'else' clause). Interesting.Aug 22 2006Tom S wrote:While we're at it, how about allowing the construct: methodName (arg, arg, ..., arg, { ... }); to be equivalent to: methodName (arg, arg, ..., arg) { ... } and methodName ({ ... }); to methodName {} Then e.g. the 'dotimes' example from 'Lazy Evaluation of Function Arguments' would become: void foo() { int x = 0; dotimes(10) { writef(x++); } } Which eliminates the need for lazy evaluation in this case, as it simply uses a delegate. Moreover, it is more readable and concise at the same time.It is a good idea and I've bandied it around before, and it has its merits. One of its problems is it only works for cases where the delegate is the last parameter. Can't have arrays of delegates like the example in http://www.digitalmars.com/d/lazy-evaluation.html. It also doesn't work where one wants the lazy evaluation function to return a value.Aug 22 2006