September 11, 2015
On Friday, 11 September 2015 at 20:16:42 UTC, Timon Gehr wrote:
> On 09/10/2015 08:23 PM, Jonathan M Davis wrote:
>>
>> That's one of the main reasons that I hate the idea of named arguments.
>> It's more stuff that's part of the API, more public stuff that you have
>> to name correctly and risk bikeshedding arguments over, and more stuff
>> that can you can't change without breaking existing code.
>>
>> - Jonathan M Davis
>
> Note that parameter names can already be determined by user code using reflection.

True, but as soon as you're doing much with reflection, all bets are off anyway, because it often becomes trivial to break code by making small changes. And I think that it's pretty clear at this point that you can't expect parameter names to not change, since they're not part of the function signature (even if compile-time reflection does let you get at them), which would not be the case if we had named arguments.

- Jonathan M Davis
September 11, 2015
On Friday, 11 September 2015 at 20:25:19 UTC, Ola Fosheim Grøstad wrote:
> On Friday, 11 September 2015 at 11:44:13 UTC, Russel Winder wrote:
>> For example https://issues.dlang.org/show_bug.cgi?id=5710
>
> If C++ interop is still important, maybe it would be a good idea to adopt C++ style lambdas.

How would that help with interop? Even if we supported passing a lambda to C++ code, the syntax wouldn't need to match, just the semantics, and that could be done without adopting C++ style lambdas in D. However, given the complexity of C++ templates, as I understand it, there are no plans to ever support them in C++ interop (since it would pretty much mean putting a C++ compiler in the D compiler), in which case, there's no need to worry about C++ lambdas anyway, because they all involve templates.

So, while C++ interop is important, and it's gotten some major improvements in the process of switching to D for the compiler front-end (and will likely continue to get improvements), there are still some pretty severe limits on what we're going to be able to do if we don't want to put a full C++ compiler inside of the D compiler, and we really don't want to be doing that.

- Jonathan M Davis
September 12, 2015
On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote:
> On 09/10/2015 10:55 AM, Prudence wrote:
> > How bout this:
> >
> > void myfunc(double delegate(int i, int z, float f)) {....}
> >
> >
> > myfunc((int i, int z, float f) { return i*z*f; } }
> >
> > vs
> >
> > myfunc({ return i*z*f; })   // Names of parameters are
> inferred from
> > signature.
>
> Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope:
>
> int i;
> myfunc({ return i*z*f; });
>
> Now, should it call another overload of myfunc that takes (int z, int f) because i is something else?
>
> Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.?
>
> Ali

As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not?

The compiler doesn't need to scan anything. It knows the which parameters from the definition!


-> void myfunc(double delegate(int i, int z, float f))  <- Compiler knows to use the names here as the default names in for the parameters when.


when used:

myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following:


1. Sees we have a block without any parameters defined. i.e., a lambda.

2. It looks up the signature of myfunc to find out what the names are

3. It sees that they are i z and f

4. Now it knows and it effectively rewrites the code as

myfunc((i,z,f) { return i*z*f; });

Surely this is not difficult, 4 steps?


September 12, 2015
On Saturday, 12 September 2015 at 01:03:54 UTC, Prudence wrote:
> On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote:
>> On 09/10/2015 10:55 AM, Prudence wrote:
>> > How bout this:
>> >
>> > void myfunc(double delegate(int i, int z, float f)) {....}
>> >
>> >
>> > myfunc((int i, int z, float f) { return i*z*f; } }
>> >
>> > vs
>> >
>> > myfunc({ return i*z*f; })   // Names of parameters are
>> inferred from
>> > signature.
>>
>> Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope:
>>
>> int i;
>> myfunc({ return i*z*f; });
>>
>> Now, should it call another overload of myfunc that takes (int z, int f) because i is something else?
>>
>> Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.?
>>
>> Ali
>
> As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not?
>
> The compiler doesn't need to scan anything. It knows the which parameters from the definition!
>
>
> -> void myfunc(double delegate(int i, int z, float f))  <- Compiler knows to use the names here as the default names in for the parameters when.
>
>
> when used:
>
> myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following:
>
>
> 1. Sees we have a block without any parameters defined. i.e., a lambda.
>
> 2. It looks up the signature of myfunc to find out what the names are
>
> 3. It sees that they are i z and f
>
> 4. Now it knows and it effectively rewrites the code as
>
> myfunc((i,z,f) { return i*z*f; });
>
> Surely this is not difficult, 4 steps?

You're making your code more brittle for a small gain. The suggestion makes parameter usage order important and the compiler can't warn about my typos.
Consider:
myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;});
Or the typo in
myfunc({return i*z+f*j;});

Lambdas are already very concise. This proposal doesn't give any benefits outside of very simple lambdas. Such lambdas are already so simple that they could use some standard functions instead (like sum, to!T, and bind).
September 12, 2015
On Saturday, 12 September 2015 at 02:13:11 UTC, Pierre Krafft wrote:
> On Saturday, 12 September 2015 at 01:03:54 UTC, Prudence wrote:
>> On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote:
>>> On 09/10/2015 10:55 AM, Prudence wrote:
>>> > How bout this:
>>> >
>>> > void myfunc(double delegate(int i, int z, float f)) {....}
>>> >
>>> >
>>> > myfunc((int i, int z, float f) { return i*z*f; } }
>>> >
>>> > vs
>>> >
>>> > myfunc({ return i*z*f; })   // Names of parameters are
>>> inferred from
>>> > signature.
>>>
>>> Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope:
>>>
>>> int i;
>>> myfunc({ return i*z*f; });
>>>
>>> Now, should it call another overload of myfunc that takes (int z, int f) because i is something else?
>>>
>>> Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.?
>>>
>>> Ali
>>
>> As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not?
>>
>> The compiler doesn't need to scan anything. It knows the which parameters from the definition!
>>
>>
>> -> void myfunc(double delegate(int i, int z, float f))  <- Compiler knows to use the names here as the default names in for the parameters when.
>>
>>
>> when used:
>>
>> myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following:
>>
>>
>> 1. Sees we have a block without any parameters defined. i.e., a lambda.
>>
>> 2. It looks up the signature of myfunc to find out what the names are
>>
>> 3. It sees that they are i z and f
>>
>> 4. Now it knows and it effectively rewrites the code as
>>
>> myfunc((i,z,f) { return i*z*f; });
>>
>> Surely this is not difficult, 4 steps?
>
> You're making your code more brittle for a small gain. The suggestion makes parameter usage order important and the compiler can't warn about my typos.
> Consider:
> myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;});
> Or the typo in
> myfunc({return i*z+f*j;});
>
> Lambdas are already very concise. This proposal doesn't give any benefits outside of very simple lambdas. Such lambdas are already so simple that they could use some standard functions instead (like sum, to!T, and bind).


What does this have to do with my proposal? Those issues exist regardless of the simplification.

myfunc({return "x:"~x~"y:"-y;}) getting changed to
myfunc({return "y:"~y~"x:"~x;});

huh? What do you mean the suggestion makes parameter usage order important? They are important, it has nothing to do with the suggestion? Are you saying that you want to reserve the right to do something like

myfunc(string delegate(string x, string y));

and

myfunc((y,x){ "y:"~y~"x:"~x; })

? If so, or unless I'm missing something, that's bad no matter what. Changing the order and reversing the names is more than just confusing, it's hard to read and most people will gloss over that fact. Be consistent with your parameters and maybe you'll have less bugs?



Or the typo in

myfunc({return i*z+f*j;});

Again, what does this have to do with anything? A typo is a typo and is always a mistake. The above example has the same effect regardless if the parameters are explicit or deduced.


myfunc((i,z,f) {return i*z+f*j;});

j is still a problem. If j is defined outside the lambda then regardless of specific or implicit parameter names, it will not cause any problems.

In either case, the compiler can see that j is either referenced outside the scope or undefined. It has nothing to do with the parameters used.


Of course maybe I'm missing something, but essentially are not almost all uses of lambda's simply copying the parameter signature of the delegate. It already infers types... you could say that leads to typo's too...



September 12, 2015
On Friday, 11 September 2015 at 23:15:58 UTC, Jonathan M Davis wrote:
> style lambdas in D. However, given the complexity of C++ templates, as I understand it, there are no plans to ever support them in C++ interop (since it would pretty much mean putting a C++ compiler in the D compiler), in which case, there's no need to worry about C++ lambdas anyway, because they all involve templates.

No, you have to generate c++ sourcecode. No need to build in the compiler.

September 12, 2015
On Saturday, 12 September 2015 at 03:32:51 UTC, Prudence wrote:
> On Saturday, 12 September 2015 at 02:13:11 UTC, Pierre Krafft wrote:
>> On Saturday, 12 September 2015 at 01:03:54 UTC, Prudence wrote:
>>> On Thursday, 10 September 2015 at 18:02:36 UTC, Ali Çehreli wrote:
>>>> On 09/10/2015 10:55 AM, Prudence wrote:
>>>> > How bout this:
>>>> >
>>>> > void myfunc(double delegate(int i, int z, float f)) {....}
>>>> >
>>>> >
>>>> > myfunc((int i, int z, float f) { return i*z*f; } }
>>>> >
>>>> > vs
>>>> >
>>>> > myfunc({ return i*z*f; })   // Names of parameters are
>>>> inferred from
>>>> > signature.
>>>>
>>>> Considering other features of the language, that's pretty much impossible in D. What if there is another i in scope:
>>>>
>>>> int i;
>>>> myfunc({ return i*z*f; });
>>>>
>>>> Now, should it call another overload of myfunc that takes (int z, int f) because i is something else?
>>>>
>>>> Should the compiler analyze the body of the code and decide which symbols could be parameters? And then go through all overloads of myfunc? etc.?
>>>>
>>>> Ali
>>>
>>> As I said, it could throw a warning or error. It, in some sense, is already a a problem with nested blocks that hide outside variables, is it not?
>>>
>>> The compiler doesn't need to scan anything. It knows the which parameters from the definition!
>>>
>>>
>>> -> void myfunc(double delegate(int i, int z, float f))  <- Compiler knows to use the names here as the default names in for the parameters when.
>>>
>>>
>>> when used:
>>>
>>> myfunc({ return i*z*f; }); <- Oh, there are the names, we know what they are because the signature is tells us. The compiler does the following:
>>>
>>>
>>> 1. Sees we have a block without any parameters defined. i.e., a lambda.
>>>
>>> 2. It looks up the signature of myfunc to find out what the names are
>>>
>>> 3. It sees that they are i z and f
>>>
>>> 4. Now it knows and it effectively rewrites the code as
>>>
>>> myfunc((i,z,f) { return i*z*f; });
>>>
>>> Surely this is not difficult, 4 steps?
>>
>> You're making your code more brittle for a small gain. The suggestion makes parameter usage order important and the compiler can't warn about my typos.
>> Consider:
>> myfunc({return "x:"~x~"y:"-y;}) getting changed to myfunc({return "y:"~y~"x:"~x;});
>> Or the typo in
>> myfunc({return i*z+f*j;});
>>
>> Lambdas are already very concise. This proposal doesn't give any benefits outside of very simple lambdas. Such lambdas are already so simple that they could use some standard functions instead (like sum, to!T, and bind).
>
>
> What does this have to do with my proposal? Those issues exist regardless of the simplification.
>
> myfunc({return "x:"~x~"y:"-y;}) getting changed to
> myfunc({return "y:"~y~"x:"~x;});
>
> huh? What do you mean the suggestion makes parameter usage order important? They are important, it has nothing to do with the suggestion? Are you saying that you want to reserve the right to do something like
>
> myfunc(string delegate(string x, string y));
>
> and
>
> myfunc((y,x){ "y:"~y~"x:"~x; })
>
> ? If so, or unless I'm missing something, that's bad no matter what. Changing the order and reversing the names is more than just confusing, it's hard to read and most people will gloss over that fact. Be consistent with your parameters and maybe you'll have less bugs?
>
>
>
> Or the typo in
>
> myfunc({return i*z+f*j;});
>
> Again, what does this have to do with anything? A typo is a typo and is always a mistake. The above example has the same effect regardless if the parameters are explicit or deduced.
>
>
> myfunc((i,z,f) {return i*z+f*j;});
>
> j is still a problem. If j is defined outside the lambda then regardless of specific or implicit parameter names, it will not cause any problems.
>
> In either case, the compiler can see that j is either referenced outside the scope or undefined. It has nothing to do with the parameters used.
>
>
> Of course maybe I'm missing something, but essentially are not almost all uses of lambda's simply copying the parameter signature of the delegate. It already infers types... you could say that leads to typo's too...

 myfunc({return "x:"~x~"y:"-y;});
is infered to mean myfunc((x,y){return "x:"~x~"y:"-y;});
while
 myfunc({return "y:"~y~"x:"~x;});
is infered to mean myfunc((y,x){return "y:"~y~"x:"~x;});
which is not what I expect since the lambda I want is myfunc((x,y){return "y:"~y~"x:"~x;});
This can lead to subtle bugs which are very hard to see.

In the typo example there could be two overloaded functions differing only in that one takes a delegate having 3 parameters and one taking a delegate having 4 parameters. If we explicitly write the lambda parameters the typo will be found since j is undefined. But when parameters are inferred the compiler will see that {return i*z + f*j;} matches the function taking a lambda with 4 parameters.

Inferred parameter types are on the brink of what I can allow. They can risk typos, but not as easily since you write the parameters twice (declaration and usage). They can also silently change if the function taking the delegate has the parameter type changed. I don't want to add more magic to that area.
September 12, 2015
On Saturday, 12 September 2015 at 10:44:05 UTC, Pierre Krafft wrote:
>  myfunc({return "x:"~x~"y:"-y;});
> is infered to mean myfunc((x,y){return "x:"~x~"y:"-y;});
> while
>  myfunc({return "y:"~y~"x:"~x;});
> is infered to mean myfunc((y,x){return "y:"~y~"x:"~x;});
> which is not what I expect since the lambda I want is myfunc((x,y){return "y:"~y~"x:"~x;});
> This can lead to subtle bugs which are very hard to see.

I don't think this is what the OP was suggesting. As far as I understand, the suggestion was that the lambda's arguments would be inferred from the function argument in higher order's function signature - not from the ones used in the lambda's body as you suggest.

So, `myfunc` will be declared as:

    void myfunc(string delegate(string x, string y)) { // ...

And when the compiler see `myfunc({return "x:"~x~"y:"-y;});`, it'll see that `x` and `y` appear in the function argument's definition and match them accordingly. This means that `myfunc({/*...*/})` will be inferred to `myfunc((x,y) {/*...*/})` no matter what the order of argument usage in the lambda's body is - because in the function's signature the arguments are `x` and `y` in that order.
September 12, 2015
On 2015-09-10 20:23, Jonathan M Davis wrote:

> That's one of the main reasons that I hate the idea of named arguments.

In Ruby named arguments need to be explicitly requested when declaring a method:

def bar(a)
  a == { a: 3 } # A hash (associative array)
end

def foo(a:)
  a == 3
end

foo(a: 3)
bar(a: 3)

Not supplying the name of the parameter in the call to "foo" would result in an error.

I think named arguments like this is way, _way_ more superior that the ridiculous idea of using an enum instead of a bool.

-- 
/Jacob Carlborg
September 12, 2015
On 2015-09-10 23:03, Meta wrote:

> You could, but then doesn't that defeat the point a bit?

No, I don't think it does. For example in Scala you can do like this:

foo(_ < _)

Which would be the same as:

foo((a, b) a < b)

But if you want to use the same parameter more than once then you cannot use the first syntax.

-- 
/Jacob Carlborg