Re: Clash When Using Function as Template Value-Parameters?

2018-05-30 Thread Vijay Nayar via Digitalmars-d

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?

2018-05-29 Thread Vijay Nayar via Digitalmars-d

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?

2018-05-29 Thread Yuxuan Shui via Digitalmars-d

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?

2018-05-29 Thread Vijay Nayar via Digitalmars-d

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?

2018-05-29 Thread Yuxuan Shui via Digitalmars-d

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?

2018-05-29 Thread Yuxuan Shui via Digitalmars-d

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?

2018-05-28 Thread Vijay Nayar via Digitalmars-d

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?

2018-05-27 Thread Daniel Kozak via Digitalmars-d
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?

2018-05-27 Thread Vijay Nayar via Digitalmars-d

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?

2018-05-26 Thread Vijay Nayar via Digitalmars-d
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?