August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Derek Parnell | Derek Parnell wrote:
> On Mon, 21 Aug 2006 14:18:04 -0700, Walter Bright wrote:
>
>
>>Frank Benoit wrote:
>>
>>>I think the lazy eval is a great feature, but in this form it has also
>>>great drawbacks.
>>>
>>>The code isn't that much readable as it was before. You don't know what
>>>will happen. Will that expression be evaluated or not? Or will it be
>>>evaluated more than once?
>>
>>It's true there is no clue from the user's side which it is. But there also isn't a clue whether the arguments are in, out, or inout. There also is no syntactic clue what the function *does*. One must look at the function interface and documentation to use it successfully anyway.
>>
>>It's going to take some caution to use this capability in a productive way.
>>
>>
>>>There is no possibility to choose between
>>>
>>>func( char[] a ) vs. func( char[] delegate() dg )
>
>
> Would it possible to use ...
>
> func ( cast(char[]) "abc" );
>
> to force the compiler to chose 'func( char[] a)' instead of the delgated
> version?
>
>
arghhh!!! Please ... cast() is only for exceptional circumstances :(
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote:
> Tom S wrote:
>
>> kris wrote:
>>
>>> Frank Benoit wrote:
>>>
>>>>> I agree with you that replacing exp with { return exp; } is clear and
>>>>> not much additional typing. But I've discovered over and over to my
>>>>> surprise that the additional typing causes people to not realize that D
>>>>> has that capability. The extra typing simply kills it.
>>>>
>>>>
>>>>
>>>> I use the { return ...; } very much. And I like it very much. And I
>>>> fully agree that the return..; is annoying, because if often use it for
>>>> a search criteria or something like that. The syntax { singlestatement }
>>>> would be pretty cool. But leaving the braces completely out it terrible.
>>>> And {} is really not too much to type.
>>>>
>>>> Imagine the terrible bugs that will occur with that. I think one of the
>>>> biggest advantages of D vs. C++ is the readability. That is so
>>>> important. Really. Please don't destroy that.
>>>
>>>
>>>
>>> I think the new sugar works really well where the code in question is *designed* around the notion of callbacks. The cues are already solidly in place at that point, so it may be less of an issue there? I'm thinking specifically of the logging examples, and some fairly advanced distributed processing paradigms.
>>>
>>> However, in typical or 'mixed' D programming, the lack of cues in this latest sugar will surely become problematic. Walter suggests the author of the callee should use an appropriate name, such that overloading would (presumeably) not be an issue and the appropriate cues would be retained. One has to wonder if that is a good idea or not.
>>>
>>> If it were possible to make the '{' '}' optional, for example, then another option would be for the coder to "make the call" as to how readable/explicit the code actually is. This is typical the case anyway, since any coder can write obfuscated code regardless of the language :)
>>>
>>> The question is then "how much different is it to add or omit the 'return' keyword?" ... personally, I think it makes a big difference; so does Walter, apparently. Thus, if we had a choice of writing these three options:
>>>
>>>
>>> # int i;
>>> # somefunk (++i);
>>> #
>>> # or
>>> #
>>> # somefunk ({++i});
>>> #
>>> # or
>>> #
>>> # somefunk (return {++i;});
>>>
>>> I think the later should be dropped, and the former two supported :)
>>
>>
>> You have a typo in the 3rd sample, it should read:
>> # somefunk ({return ++i;});
>>
>> ... which clearly shows that the 3rd option isn't the preferred one ;)
>
>
> I'm not sure I'd want to do away with option 3 unless option 2 supported multiple statements and a void return in a way that made sense.
>
>
> Sean
True; and some have pointed out potential problems with #2.
It's worth noting that C# uses the '=>' operator for the equivalent sugar: IIRC the equivalent example in C# would be
# somefunk (i => ++i);
so, perhaps, just perhaps, it's worth introducing an operator (*gasp*) specifically to make this completely unambiguous? For example:
# somefunk (@++i);
where '@' (or whatever) would be a low-priority operator ?
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to kris | kris wrote:
> Derek Parnell wrote:
>> On Mon, 21 Aug 2006 14:18:04 -0700, Walter Bright wrote:
>>
>>
>>> Frank Benoit wrote:
>>>
>>>> I think the lazy eval is a great feature, but in this form it has also
>>>> great drawbacks.
>>>>
>>>> The code isn't that much readable as it was before. You don't know what
>>>> will happen. Will that expression be evaluated or not? Or will it be
>>>> evaluated more than once?
>>>
>>> It's true there is no clue from the user's side which it is. But there also isn't a clue whether the arguments are in, out, or inout. There also is no syntactic clue what the function *does*. One must look at the function interface and documentation to use it successfully anyway.
>>>
>>> It's going to take some caution to use this capability in a productive way.
>>>
>>>
>>>> There is no possibility to choose between
>>>>
>>>> func( char[] a ) vs. func( char[] delegate() dg )
>>
>>
>> Would it possible to use ...
>>
>> func ( cast(char[]) "abc" );
>>
>> to force the compiler to chose 'func( char[] a)' instead of the delgated
>> version?
>>
>>
>
>
>
> arghhh!!! Please ... cast() is only for exceptional circumstances :(
cast( :-) )
( arghhh!!! Please ... cast() is only for exceptional circumstances :( );
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Derek Parnell | Derek Parnell wrote:
> On Mon, 21 Aug 2006 14:18:04 -0700, Walter Bright wrote:
>
>> Frank Benoit wrote:
>>> I think the lazy eval is a great feature, but in this form it has also
>>> great drawbacks.
>>>
>>> The code isn't that much readable as it was before. You don't know what
>>> will happen. Will that expression be evaluated or not? Or will it be
>>> evaluated more than once?
>> It's true there is no clue from the user's side which it is. But there also isn't a clue whether the arguments are in, out, or inout. There also is no syntactic clue what the function *does*. One must look at the function interface and documentation to use it successfully anyway.
>>
>> It's going to take some caution to use this capability in a productive way.
>>
>>> There is no possibility to choose between
>>>
>>> func( char[] a ) vs. func( char[] delegate() dg )
>
> Would it possible to use ...
>
> func ( cast(char[]) "abc" );
>
> to force the compiler to chose 'func( char[] a)' instead of the delgated
> version?
>
>
As for ambiguity between overloads, doesn't it make more sense to change the overloading rules so that 'func( char[] a)' takes precedence, if this can be done?
I'd think that it would make sense as it is similar to how implicit conversions for integral types work. The {} syntax would then 'force' the second form to be taken, but this is no cast.
Then again, I could be very wrong.
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tom S |
> Just as Walter stated, that's the same case as with 'in' vs 'inout' vs 'out' arguments. You don't know what will happen in either case
If an argument is in/out/inout it is clear from the content and context. If it is out, you call the function to get something.
lazy-eval syntax
When I code, I often guess what the method is called and what arguments
it has.
For example i have a container with a add( element ) method. Now this
method is implemented with lazy-eval, if the container is already full,
the argument is not evaluated.
Or the get( index ) method does not eval the arg if the container is
empty. And every time I have not only to remember the method name and
arguments, now I have to know details of the implementation.
Great, that was the silly thing they wanted to take away from me with
this OOP ;)
Solution: Force the user the make {} around a delegate argument.
Now I get a compiler error when writing container.get(i++); Then I know,
this is a delegate, take care with the increment, writing
container.get({i}); i++;
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to kris |
> If it were possible to make the '{' '}' optional, for example, then another option would be for the coder to "make the call" as to how readable/explicit the code actually is. This is typical the case anyway, since any coder can write obfuscated code regardless of the language :)
>
Writing it without {} will always be obfuscating, if the reader doesn't know what will happen from the function names. And a good function name does perhaps not imply a delegate call to another person reading the code.
The {} can make that clear, and they leave the user the choice to call the overloaded function without lazy eval.
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Benoit | Frank Benoit wrote:
>> Just as Walter stated, that's the same case as with 'in' vs 'inout' vs
>> 'out' arguments. You don't know what will happen in either case
>
> If an argument is in/out/inout it is clear from the content and context.
> If it is out, you call the function to get something.
>
> lazy-eval syntax
> When I code, I often guess what the method is called and what arguments
> it has.
> For example i have a container with a add( element ) method. Now this
> method is implemented with lazy-eval, if the container is already full,
> the argument is not evaluated.
> Or the get( index ) method does not eval the arg if the container is
> empty. And every time I have not only to remember the method name and
> arguments, now I have to know details of the implementation.
Nah, just that the arg might be left not-evaluated... I wouldn't use it with functions like 'get' or 'set' but with stuff for which it makes sense, just like with 'assert'.
I'm just trying to defend a point I don't really believe... You're probably right, the implicit approach brings more traps than advantages :(
--
Tomasz Stachowiak
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tom S |
> I'm just trying to defend a point I don't really believe... You're probably right, the implicit approach brings more traps than advantages :(
Yes, and that is my only point.
delegate arguments will become a often used feature. Well, I like to use
them since 0.163.
But without making them explicit, they will make D to hell. I see me
sitting at night, staring at the same code, and after hours of debugging
"NOOOO, its a delegate!!!"
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Benoit | Frank Benoit wrote:
> For example i have a container with a add( element ) method. Now this
> method is implemented with lazy-eval, if the container is already full,
> the argument is not evaluated.
> Or the get( index ) method does not eval the arg if the container is
> empty. And every time I have not only to remember the method name and
> arguments, now I have to know details of the implementation.
> Great, that was the silly thing they wanted to take away from me with
> this OOP ;)
>
> Solution: Force the user the make {} around a delegate argument.
>
> Now I get a compiler error when writing container.get(i++); Then I know,
> this is a delegate, take care with the increment, writing
> container.get({i}); i++;
While I understand your concern, I don't think the examples illustrate it. If a get() is done for an element that doesn't exist, the usual way to deal with it is throw an exception, and have some complex scheme to try and undo the side effects from evaluating the argument. With lazy evaluation, no need to undo the side effects, as only if the get() is guaranteed to succeed will the argument be evaluated.
The problem with requiring the { } around the argument is that programmers just don't like it. I don't think I can make them like it.
|
August 21, 2006 Re: Lazy eval | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> Frank Benoit wrote:
>
>> For example i have a container with a add( element ) method. Now this
>> method is implemented with lazy-eval, if the container is already full,
>> the argument is not evaluated.
>> Or the get( index ) method does not eval the arg if the container is
>> empty. And every time I have not only to remember the method name and
>> arguments, now I have to know details of the implementation.
>> Great, that was the silly thing they wanted to take away from me with
>> this OOP ;)
>>
>> Solution: Force the user the make {} around a delegate argument.
>>
>> Now I get a compiler error when writing container.get(i++); Then I know,
>> this is a delegate, take care with the increment, writing
>> container.get({i}); i++;
>
>
> While I understand your concern, I don't think the examples illustrate it. If a get() is done for an element that doesn't exist, the usual way to deal with it is throw an exception, and have some complex scheme to try and undo the side effects from evaluating the argument. With lazy evaluation, no need to undo the side effects, as only if the get() is guaranteed to succeed will the argument be evaluated.
>
> The problem with requiring the { } around the argument is that programmers just don't like it. I don't think I can make them like it.
Can you at least make it optional? Or, can you come up with an operator or something that is low-impact? Making this unambiguous instead would surely be a win-win?
|
Copyright © 1999-2021 by the D Language Foundation