Jump to page: 1 2
Thread overview
even more delegate sugar
Aug 21, 2006
Tom S
Aug 22, 2006
Don Clugston
Aug 22, 2006
Oskar Linde
Aug 22, 2006
Don Clugston
Aug 22, 2006
Oskar Linde
Aug 22, 2006
Tom S
Aug 22, 2006
Don Clugston
Aug 22, 2006
Tom S
Aug 22, 2006
Don Clugston
Aug 22, 2006
Ivan Senji
Aug 23, 2006
Walter Bright
August 21, 2006
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
August 22, 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.
August 22, 2006
Don Clugston wrote:
> 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 {}

Just as I and others have suggested already. I really like it.

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

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 ';'"

> 
> 
> 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
August 22, 2006
Don Clugston wrote:
> 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.

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? :P
August 22, 2006
Oskar Linde wrote:
> Don Clugston wrote:
>> 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 {}
> 
> Just as I and others have suggested already. I really like it.
> 
>>>
>>>
>>> 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.
> 
> Would they? (assuming there is no dotimes overload with only one argument)

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

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

On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.
August 22, 2006
Don Clugston wrote:
> Oskar Linde wrote:
>> Don Clugston wrote:
>>> Tom S wrote:
>>>> 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.
>>
>> Would they? (assuming there is no dotimes overload with only one argument)
> 
> 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).

You are correct, of course.

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

> 
>>> 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.
> 
> On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.

break would pose a problem though.
August 22, 2006
Oskar Linde wrote:
> Don Clugston wrote:
>> Oskar Linde wrote:
>>> Don Clugston wrote:
>>>> Tom S wrote:
>>>>> 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.
>>>
>>> Would they? (assuming there is no dotimes overload with only one argument)
>>
>> 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).
> 
> You are correct, of course.

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.


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

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.


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


>>>> 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.
>>
>> On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.
> 
> break would pose a problem though.

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 Stachowiak
August 22, 2006
Oskar Linde wrote:
> Don Clugston wrote:
>> Oskar Linde wrote:
>>> Don Clugston wrote:
>>>> Tom S wrote:
>>>>> 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.
>>>
>>> Would they? (assuming there is no dotimes overload with only one argument)
>>
>> 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).
> 
> You are correct, of course.
> 
>> 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.

Touché. I forgot about that.

Indeed
for (int=0;i<10;++i);
{
  printf("%d", i);
}
is valid C code, and the proposal is certainly no worse than that.

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

It would also be nice to be able to do something with the related example:
methodName(int x, void delegate(void) dg[] ... )

but I don't think it's practical.

methodName(7) { writefln("first"); } with { writefln("second")} with { writefln("third"); }

Unconvincing.

>> On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.
> 
> break would pose a problem though.

You're right.
Although foreach with opApply has the same problem.
August 22, 2006
Don Clugston wrote:
> Oskar Linde wrote:
>> Don Clugston wrote:
>>> On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.
>>
>> break would pose a problem though.
> 
> You're right.
> Although foreach with opApply has the same problem.

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 ;)
August 22, 2006
Tom S wrote:
> Don Clugston wrote:
>> Oskar Linde wrote:
>>> Don Clugston wrote:
>>>> On reflection, an even more interesting example is variants of foreach, which I think would become completely redundant.
>>>
>>> break would pose a problem though.
>>
>> You're right.
>> Although foreach with opApply has the same problem.
> 
> 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.

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

> 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 ;)
« First   ‹ Prev
1 2