Feedback Thread: DIP 1033--Implicit Conversion of Expressions to Delegates--Final Review

Walter Bright newshound2 at
Sun Nov 22 08:46:16 UTC 2020

On 11/20/2020 4:40 PM, MD-39 wrote:
> There's a few problems and some things I don't really agree with. I'll start 
> with the most obvious problem regarding the example with absolutePath.
>> pure @safe string absolutePath(string path, string delegate() base = getcwd());
> This becomes (per the DIP):
> pure @safe string absolutePath(string path, string delegate() base = () @trusted 
> { return getcwd() });
> Which would still give an error, though the delegate encapsulating getcwd() is 
> auto inferred, the actually parameter isn't auto inferred according to existing 
> rules.
> The parameter `base` is both impure and @unsafe. Unless there is some auto 
> inference happening here this would fail to compile. It wouldn't be used the 
> same way, the implementation would have to change to assume `base` is pure and 
> @safe.
> If there is auto inference of parameter types, the DIP needs to outline the 
> details for this. Again, it would still be impure even if it auto inferred to be 
> @trusted from `getcwd`. So again, the implementation would have to change to 
> assume `base` is pure.
> In either case, the code is broken and/or is giving the illusion that the 
> problem at hand is simpler than it actually is by masking implementation details.

It won't compile, and that seems correct to me.

> The DIP also doesn't go over one of the common discussions regarding lazy that 
> is brought up from time to time; in regards to readability. This would be a good 
> case to implement it. For example in C# at the call site the keyword `ref` has 
> to be added when passing an argument to a ref parameter. Similarly you would 
> just use a lambda `() =>` in C#, there is no special case to implicitly convert 
> to a delegate.

The C# style makes refactoring code harder. Instead of modifying the callee, you 
have to additionally modify all of the callers.

>> int delegate() dg = () { return 3; };
>> int delegate() dg = () => 3;
>> int delegate() dg = { return 3; };
>> int delegate() dg = 3;
> When you have 4 ways to express the exact same thing, there is an obvious design 
> problem. You shouldn't need 4 different ways to express the same thing.

This comes from the desire to dispense with unnecessary syntax.

> The existing Lambda syntax already has a lot of confusion, it isn't uncommon for 
> individuals to mistakenly do the following:
>      auto dg = x => { return x * x; };
> Which doesn't do what it appears to do.
> This would introduce syntax that can be similarly misunderstood. AS follows, the 
> similar syntax can be used today. This code may not be common but it illustrates 
> the commonality in the syntax, as calling a function doesn't require the `()` 
> parenthesis.
>      alias FooDelegate = int delegate();
>      struct A {
>          FooDelegate a() { return null; }
>      }
>      void main()
>      {
>          A a;
>          int delegate() t = a.a;
>      }
> In summation, this is just replacing something that already was and is repeating 
> past mistake*s*. Ultimately this is just syntax sugar to avoid 4 characters `() 
> =>`. The justification is flimsy (along with errors in the DIP)

Please be explicit about errors in the DIP, as just saying there are errors in 
the DIP is not helpful.

> and the benefit 
> isn't outweighed by the hit to readability and the potential for that 
> improvement by requiring to just define a delegate.

It doesn't introduce new syntax, and the point of lazy is to enable lazy 
evaluation of arguments without having to use delegate syntax. All this does is 
replace the 'lazy' with the delegate syntax. D already uses this for variadic 
lazy arguments, and nothing has come up bad about it.

More information about the Digitalmars-d mailing list