digitalmars.D - non-lambda overloads for lambda-only things
- Steven Schveighoffer (21/21) Apr 15 2021 Have you ever written something like:
- Jordan Wilson (8/29) Apr 15 2021 As a noob, when I see error messages like the first one, I
- =?UTF-8?Q?Ali_=c3=87ehreli?= (30/37) Apr 15 2021 YES! :)
- Berni44 (7/8) Apr 15 2021 YES! When I was a beginner, I did not know about templates
- Jacob Carlborg (10/23) Apr 16 2021 Yes, definitely. I doesn't help when there are longer chains and they're...
- Steven Schveighoffer (5/29) Apr 16 2021 It could possibly work, if you specify the type. But I haven't thought
- Paul Backus (6/17) Apr 16 2021 You'd have to use `&` if you wanted to pass a named function
- tsbockman (55/61) Apr 16 2021 When a function or delegate is passed as a runtime argument, it
- tsbockman (16/20) Apr 16 2021 Rather than adding a bunch of boiler plate to every generic
- Steven Schveighoffer (4/27) Apr 16 2021 Yes please! Can someone do this? Would be way better than the phobos
- Jon Degenhardt (7/28) Apr 16 2021 Yes!! As others have said, this hit me when I first started
Have you ever written something like: auto str = "hello".map(r => r.toUpper).array; and been confronted with fun errors like: Error: template std.algorithm.iteration.map cannot deduce function from argument types !()(string, void), candidates are: /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/iteration.d(479): map(fun...) with fun = () must satisfy the following constraint: fun.length >= 1 What the hell is the "fun length"? This is not FUN!!! In any case, I thought of maybe adding something like this: void map()(...) { static assert(false, "You didn't mean to do this. Make your lambda a template parameter"); } To instead get a better error message: Error: static assert: "You didn't mean to do this. Make your lambda a template parameter" Is this worth adding to Phobos? -Steve
Apr 15 2021
On Thursday, 15 April 2021 at 22:02:10 UTC, Steven Schveighoffer wrote:Have you ever written something like: auto str = "hello".map(r => r.toUpper).array; and been confronted with fun errors like: Error: template std.algorithm.iteration.map cannot deduce function from argument types !()(string, void), candidates are: /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/iteration.d(479): map(fun...) with fun = () must satisfy the following constraint: fun.length >= 1 What the hell is the "fun length"? This is not FUN!!! In any case, I thought of maybe adding something like this: void map()(...) { static assert(false, "You didn't mean to do this. Make your lambda a template parameter"); } To instead get a better error message: Error: static assert: "You didn't mean to do this. Make your lambda a template parameter" Is this worth adding to Phobos? -SteveAs a noob, when I see error messages like the first one, I immediately just pick out the line number, and just stare at the offending code until I realise I've missed an "!". I think your proposed error message tells me instantly what went wrong. Thanks, Jordan
Apr 15 2021
On 4/15/21 3:02 PM, Steven Schveighoffer wrote:Have you ever written something like: auto str = "hello".map(r => r.toUpper).array;To instead get a better error message: Error: static assert: "You didn't mean to do this. Make your lambda a template parameter" Is this worth adding to Phobos? -SteveYES! :) Coincidentally, I have wasted considerable amount of time just now with the following error message: import std.format; import std.algorithm; void main() { auto content = q"EOS 1 first line 2 second line EOS"; foreach (line; content) { int i; string s; line.formattedRead!"%s %s"(i, s); } } The first line of the 78-line error message is this: /usr/include/dmd/phobos/std/format.d(1492): Error: template `std.range.primitives.empty` cannot deduce function from argument types `!()(immutable(char))`, candidates are: but the line in format.d, which my editor was showing me was this: assert(!r.empty, "Required at least one more input"); I admit that my brain was reading the error message on the source code instead of the actual error message and I was scratching my head, trying to understand what "one more input" meant. The programmer's error was something completely different: 'content' is not an iterable thing; it's a string. Argh! So, one solution is to iterate over content.splitter('\n') in the loop. Ali
Apr 15 2021
On Thursday, 15 April 2021 at 22:02:10 UTC, Steven Schveighoffer wrote:Is this worth adding to Phobos?YES! When I was a beginner, I did not know about templates parameters. I realized soon, that I sometimes need a `!` to make a function, like `std.conv : to` from Phobos work, but was quite often lost, when getting such "fun" error messages. A hint toward a template parameter would have helped a lot.
Apr 15 2021
On 2021-04-16 00:02, Steven Schveighoffer wrote:Have you ever written something like: auto str = "hello".map(r => r.toUpper).array; and been confronted with fun errors like: Error: template std.algorithm.iteration.map cannot deduce function from argument types !()(string, void), candidates are: /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/iteration.d(479): map(fun...) with fun = () must satisfy the following constraint: fun.length >= 1Yes, definitely. I doesn't help when there are longer chains and they're nested. It usually results in even more cryptic error messages. BTW, what's stopping us from supporting the above syntax? Why do we still pass the lambda as a template argument? In that past, before proper support for lambdas, there was a use case to pass a string literal, which must be passed as a template argument. If DMD cannot inline the lambda, who cares, use LDC instead. -- /Jacob Carlborg
Apr 16 2021
On 4/16/21 7:23 AM, Jacob Carlborg wrote:On 2021-04-16 00:02, Steven Schveighoffer wrote:It could possibly work, if you specify the type. But I haven't thought about the ramifications. I want to avoid creating closures, and as you say, inlining might be affected. -SteveHave you ever written something like: auto str = "hello".map(r => r.toUpper).array; and been confronted with fun errors like: Error: template std.algorithm.iteration.map cannot deduce function from argument types !()(string, void), candidates are: /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/iteration.d(479): map(fun...) with fun = () must satisfy the following constraint: fun.length >= 1Yes, definitely. I doesn't help when there are longer chains and they're nested. It usually results in even more cryptic error messages. BTW, what's stopping us from supporting the above syntax? Why do we still pass the lambda as a template argument? In that past, before proper support for lambdas, there was a use case to pass a string literal, which must be passed as a template argument. If DMD cannot inline the lambda, who cares, use LDC instead.
Apr 16 2021
On Friday, 16 April 2021 at 14:02:24 UTC, Steven Schveighoffer wrote:On 4/16/21 7:23 AM, Jacob Carlborg wrote:You'd have to use `&` if you wanted to pass a named function rather than a lambda (e.g., `map(&fun)`), and you wouldn't be able to pass template functions (e.g., `map(&to!string)` would be a compile-time error).BTW, what's stopping us from supporting the above syntax? Why do we still pass the lambda as a template argument? In that past, before proper support for lambdas, there was a use case to pass a string literal, which must be passed as a template argument. If DMD cannot inline the lambda, who cares, use LDC instead.It could possibly work, if you specify the type. But I haven't thought about the ramifications. I want to avoid creating closures, and as you say, inlining might be affected.
Apr 16 2021
On Friday, 16 April 2021 at 11:23:07 UTC, Jacob Carlborg wrote:BTW, what's stopping us from supporting the above syntax? Why do we still pass the lambda as a template argument? In that past, before proper support for lambdas, there was a use case to pass a string literal, which must be passed as a template argument. If DMD cannot inline the lambda, who cares, use LDC instead.When a function or delegate is passed as a runtime argument, it cannot be inlined unless the function it is being passed to is also inlined. But, when one is passed as a template argument it can be inlined even if the function receiving it cannot or should not be inlined. This limitation is fundamental to the language, not a weakness of any particular implementation: ```D module app; auto fRT(int function(int) g, int x) { pragma(inline, false); // For demonstration purposes. return g(x * 7); } auto fCT(alias g)(int x) if(is(typeof(g) : int function(int))) { pragma(inline, false); // For demonstration purposes. return g(x * 7); } void main() { import std.stdio : writeln; /* g cannot be inlined in fRT, because g may be different every time f is called: */ writeln(fRT((int y) { return y + 3; }, 4)); writeln(fRT((int y) { return y - 2; }, 2)); /* But, g can be inlined in some possible instantiations of fCT, because each instantiation is a separate function at runtime: */ writeln(fCT!((int y) { return y + 3; })(4)); writeln(fCT!((int y) { return y - 2; })(2)); } ``` Part of the resulting assembly code with LDC `-m64 -mcpu=haswell -O3 -release`: ``` int app.fRT(int function(int)*, int): lea eax, [8*rdi] sub eax, edi mov edi, eax jmp rsi pure nothrow nogc safe int app.fCT!(app.main().__lambda3(int)).fCT(int): lea eax, [8*rdi] sub eax, edi add eax, 3 ret pure nothrow nogc safe int app.fCT!(app.main().__lambda4(int)).fCT(int): lea eax, [8*rdi] sub eax, edi add eax, -2 ret ```
Apr 16 2021
On Thursday, 15 April 2021 at 22:02:10 UTC, Steven Schveighoffer wrote:To instead get a better error message: Error: static assert: "You didn't mean to do this. Make your lambda a template parameter" Is this worth adding to Phobos?Rather than adding a bunch of boiler plate to every generic library to get better error messages, why not make the compiler do it automatically? Whenever the compiler generates an error message due to failure of function overload resolution and only runtime arguments were supplied (syntactically), the compiler could first test whether overload resolution would have succeeded if a `!` had been included to mark them as template arguments, instead. It should still be an error either way, but in the latter case a "did you mean ...?" suggested resolution could be included in the message. This generally shouldn't slow down compilation meaningfully, since it only triggers when the compilation is going to fail and skip code generation, etc. anyway.
Apr 16 2021
On 4/16/21 4:36 PM, tsbockman wrote:On Thursday, 15 April 2021 at 22:02:10 UTC, Steven Schveighoffer wrote:Yes please! Can someone do this? Would be way better than the phobos hack I am thinking of. -SteveTo instead get a better error message: Error: static assert: "You didn't mean to do this. Make your lambda a template parameter" Is this worth adding to Phobos?Rather than adding a bunch of boiler plate to every generic library to get better error messages, why not make the compiler do it automatically? Whenever the compiler generates an error message due to failure of function overload resolution and only runtime arguments were supplied (syntactically), the compiler could first test whether overload resolution would have succeeded if a `!` had been included to mark them as template arguments, instead. It should still be an error either way, but in the latter case a "did you mean ...?" suggested resolution could be included in the message. This generally shouldn't slow down compilation meaningfully, since it only triggers when the compilation is going to fail and skip code generation, etc. anyway.
Apr 16 2021
On Thursday, 15 April 2021 at 22:02:10 UTC, Steven Schveighoffer wrote:Have you ever written something like: auto str = "hello".map(r => r.toUpper).array; and been confronted with fun errors like: Error: template std.algorithm.iteration.map cannot deduce function from argument types !()(string, void), candidates are: /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/iteration.d(479): map(fun...) with fun = () must satisfy the following constraint: fun.length >= 1 What the hell is the "fun length"? This is not FUN!!! In any case, I thought of maybe adding something like this: void map()(...) { static assert(false, "You didn't mean to do this. Make your lambda a template parameter"); } To instead get a better error message: Error: static assert: "You didn't mean to do this. Make your lambda a template parameter" Is this worth adding to Phobos? -SteveYes!! As others have said, this hit me when I first started learning D. I just wasn't expecting to pass the lambda as a template parameter. An error message that more quickly pointed to what needed to be done would have removed a start-up barrier. --Jon
Apr 16 2021