Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 19:17:37 UTC, Vijay Nayar wrote: On Tuesday, 29 May 2018 at 12:58:20 UTC, Yuxuan Shui wrote: [...] I tried this again, this time completely ignoring lambdas and completely specifying the desired type like so: [...] Issue created: https://issues.dlang.org/show_bug.cgi?id=18917
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 12:58:20 UTC, Yuxuan Shui wrote: I believe that is the case. Normally that will be fine, because you can't modify them. Type-deduced lambda is a very special case, as in their parameter types are deduced on first use, so in a sense, they are "modified" by the first instantiation. BTW, I can't find the documentation about defining lambda with their parameter types omitted anywhere. I tried this again, this time completely ignoring lambdas and completely specifying the desired type like so: final class BTree( ValueT, KeyT = ValueT, const(KeyT) function(ValueT) nothrow pure @nogc KeyF = function KeyT(ValueT a) { return a; }) { KeyT getKey(ValueT val) { return KeyF(val); } } But unfortunately, the following code still produces an error: void main() { auto btree1 = new BTree!(char); auto btree2 = new BTree!(int); // The error is on this line. } onlineapp.d(17): Error: template instance `BTree!int` does not match template declaration `BTree(ValueT, KeyT = ValueT, const(char) function(char) pure nothrow @nogc KeyF = function KeyT(ValueT a) { return a; } )` I think at this point this may be a bug in the compiler. What do you think?
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 12:37:04 UTC, Vijay Nayar wrote: On Tuesday, 29 May 2018 at 11:36:11 UTC, Yuxuan Shui wrote: No, wait a second. (a)=>a is in default argument list, so it is in the global scope. And it was instantiated when you instantiate BTree with char. Could you explain that part a bit for me? Yes, (a) => a is a default value, but when you say it is in the global scope, are you saying that a single object "(a) => a" is created in the global scope and not created for each template argument list, e.g. "BTree!int" and "BTree!char"? I actually do not know in what scope such objects would be created, I had assumed it was per template-parameter list, but are you saying this is not the case? I believe that is the case. Normally that will be fine, because you can't modify them. Type-deduced lambda is a very special case, as in their parameter types are deduced on first use, so in a sense, they are "modified" by the first instantiation. BTW, I can't find the documentation about defining lambda with their parameter types omitted anywhere.
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 11:36:11 UTC, Yuxuan Shui wrote: No, wait a second. (a)=>a is in default argument list, so it is in the global scope. And it was instantiated when you instantiate BTree with char. Could you explain that part a bit for me? Yes, (a) => a is a default value, but when you say it is in the global scope, are you saying that a single object "(a) => a" is created in the global scope and not created for each template argument list, e.g. "BTree!int" and "BTree!char"? I actually do not know in what scope such objects would be created, I had assumed it was per template-parameter list, but are you saying this is not the case?
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 11:34:03 UTC, Yuxuan Shui wrote: On Saturday, 26 May 2018 at 11:56:30 UTC, Vijay Nayar wrote: I've been experimenting with code that uses std.functional : binaryFun and unaryFun, but I have found that using these methods makes it impossible to add function attributes like @safe, @nogc, pure, and nothrow, because no guarantee can be made about the functions created via a stream. For example, if you expect a comparator function like "a == b", someone can pass in "a.data--" instead. [...] This is probably a bug. BTree!char.lambda is clearly not the same as BTree!int.lambda, but the compiler seems to disagree? No, wait a second. (a)=>a is in default argument list, so it is in the global scope. And it was instantiated when you instantiate BTree with char.
Re: Clash When Using Function as Template Value-Parameters?
On Saturday, 26 May 2018 at 11:56:30 UTC, Vijay Nayar wrote: I've been experimenting with code that uses std.functional : binaryFun and unaryFun, but I have found that using these methods makes it impossible to add function attributes like @safe, @nogc, pure, and nothrow, because no guarantee can be made about the functions created via a stream. For example, if you expect a comparator function like "a == b", someone can pass in "a.data--" instead. [...] This is probably a bug. BTree!char.lambda is clearly not the same as BTree!int.lambda, but the compiler seems to disagree?
Re: Clash When Using Function as Template Value-Parameters?
On Sunday, 27 May 2018 at 20:38:25 UTC, Daniel Kozak wrote: I would rewrite it to something like this: template BTree(ValueT, KeyT = ValueT,alias KeyF = unaryFun!"cast(const)a") { class BTree { This is roughly what I originally had, but it creates a number of problems that I wanted to get around. Changing KeyF back to an alias means that any function that uses it can no longer be const, pure, @nogc, or nothrow. Essentially the parameter is just anything the user provides. If I use a template value-parameter, then it forces any lambda the user passes in to either match the type I enter in (with const, pure, etc.) or the program to fail to compile. That is, I don't want the user to pass in any function, but only functions with the desired attributes. I.e., I wouldn't want them to pass in for KeyF something like "a.data--". Listing out the full type does indeed work correctly with various examples, and letting the user pass in something like `a => a._id` does compile, but the only problem is that when there are two such template instances in the same program. Logically `BTree!(MyStruct, int, a => a.id)`, `BTree!(AnotherStruct, char, a => a.name[0])`, `BTree!int` and `BTree!char` should all be totally independent. But for reasons unknown, the individual parameters seems to be swapped and and confused during compilation. In the error above I listed. The function parameter from `BTree!char` is being used to create a compile error against `BTree!int`, which is very odd. Each of these classes compile and run just fine individually, the compilation only breaks when both exist.
Re: Clash When Using Function as Template Value-Parameters?
I would rewrite it to something like this: import std.stdio; import std.functional; template BTree(ValueT, KeyT = ValueT,alias KeyF = unaryFun!"cast(const)a") { class BTree { auto getKey(ValueT val) { return KeyF(val); } } } void main() { auto btree1 = new BTree!(char)(); // Removing this line eliminates the error. auto btree2 = new BTree!(int)(); } On Sun, May 27, 2018 at 9:03 AM, Vijay Nayar via Digitalmars-d < digitalmars-d@puremagic.com> wrote: > On Saturday, 26 May 2018 at 11:56:30 UTC, Vijay Nayar wrote: > >> The error is: >> ``` >> onlineapp.d(8): Error: function literal `__lambda6(char a)` is not >> callable using argument types `(int)` >> onlineapp.d(8):cannot pass argument `val` of type `int` to >> parameter `char a` >> onlineapp.d(15): Error: template instance `onlineapp.BTree!(int, int, >> function (char a) => a)` error instantiating >> ``` >> > > Just to clarify. In the example above, if I create a 'BTree!int' by > itself, it's fine. If I create a 'BTree!char' by itself, it's fine also. > But if I create both, even if they are created in different modules, the > compiler seems to mix up the types of the function template-parameter, and > tries to fit a 'char' to the 'int' function or an 'int' to the 'char' > function, depending on which was declared first. >
Re: Clash When Using Function as Template Value-Parameters?
On Saturday, 26 May 2018 at 11:56:30 UTC, Vijay Nayar wrote: The error is: ``` onlineapp.d(8): Error: function literal `__lambda6(char a)` is not callable using argument types `(int)` onlineapp.d(8):cannot pass argument `val` of type `int` to parameter `char a` onlineapp.d(15): Error: template instance `onlineapp.BTree!(int, int, function (char a) => a)` error instantiating ``` Just to clarify. In the example above, if I create a 'BTree!int' by itself, it's fine. If I create a 'BTree!char' by itself, it's fine also. But if I create both, even if they are created in different modules, the compiler seems to mix up the types of the function template-parameter, and tries to fit a 'char' to the 'int' function or an 'int' to the 'char' function, depending on which was declared first.
Clash When Using Function as Template Value-Parameters?
I've been experimenting with code that uses std.functional : binaryFun and unaryFun, but I have found that using these methods makes it impossible to add function attributes like @safe, @nogc, pure, and nothrow, because no guarantee can be made about the functions created via a stream. For example, if you expect a comparator function like "a == b", someone can pass in "a.data--" instead. That being said, I started trying out using strongly typed and attributed template parameters instead, relying on lambdas to keep the syntax for the user short. But when I tried this, I found that the very existence of templates with different parameter values causes a collision during compilation. The following code snippet demonstrates the error: ``` import std.stdio; final class BTree( ValueT, KeyT = ValueT, const(KeyT) function(ValueT) @safe @nogc nothrow pure KeyF = (a) => a) { KeyT getKey(ValueT val) { return KeyF(val); } } void main() { auto btree1 = new BTree!(char); // Removing this line eliminates the error. auto btree2 = new BTree!(int); } ``` The error is: ``` onlineapp.d(8): Error: function literal `__lambda6(char a)` is not callable using argument types `(int)` onlineapp.d(8):cannot pass argument `val` of type `int` to parameter `char a` onlineapp.d(15): Error: template instance `onlineapp.BTree!(int, int, function (char a) => a)` error instantiating ``` Is this an error in the compiler or in my own understanding of the D language?