Thread overview
Is using function() in templates possible at all?
Apr 11, 2018
Sjoerd Nijboer
Apr 11, 2018
Alex
Apr 11, 2018
Sjoerd Nijboer
Apr 12, 2018
Nicholas Wilson
Apr 12, 2018
Laurent Tréguier
Apr 12, 2018
Alex
Apr 12, 2018
Laurent Tréguier
April 11, 2018
I am trying to do a binary insert into my sorted array.
To sort classes and structs I would like to give a delegate `(t) => t.myValue` to sort on that value whitout having to implement an interface or specifically declare opCmp for every class I want to have sorted.
After all, I might want one group of objects of a given class sorted in one way and another group of objects sorted on another way depending on the usecase.
In C# this is done by passing on a lambda in for instance a LinQ expression to sort such list after insertion, and is also usefull in other circumstances.

But is it possible in D to do something simular but then pass on this Function() during compile time?

something like
`
void main() { SortedList!(Vector3, (v) => v.y) list; }

struct Vector3 { float x, y, z; }

class SortedList(T, int function(T) comparer)
{
	T[] array;
	
	int foo(T t)
	{
		for(int i = 0; i < array.lenght; i++)
		{
			if(comparer(this.otherT) <=  comparer(t))
			{
				//do stuff
				array[i] = t;
			}
		}
	}
}
`

April 11, 2018
On Wednesday, 11 April 2018 at 21:07:03 UTC, Sjoerd Nijboer wrote:

> class SortedList(T, int function(T) comparer)

I would say, alias template parameter is your friend.
https://dlang.org/spec/template.html#TemplateAliasParameter

´´´
import std.stdio;
import std.range;

void main()
{
	auto list = new SortedList!(Vector3, v => v.y)();

	assert(list.array.empty);
	list.foo(Vector3.init);
}

struct Vector3 { float x, y, z; }

class SortedList(T, alias comparer)
{
	T[] array;
	
	auto foo(T t)
	{
		for(int i = 0; i < array.length; i++)
		{
			if(comparer(this.array[i]) <=  comparer(t))
			{
				//do stuff
				array[i] = t;
			}
		}
	}
}
´´´
April 11, 2018
On Wednesday, 11 April 2018 at 21:29:27 UTC, Alex wrote:
> I would say, alias template parameter is your friend.
> https://dlang.org/spec/template.html#TemplateAliasParameter
>
> class SortedList(T, alias comparer)

It works, thank you!
But just to be shure, there's no way to have this more strongly typed in D so I can enforce that `comparer`is a funciton or delegate with a specific defenition?
Right now i'm relying on the template to error on some different place which might not give such a readable error message to the user.
April 12, 2018
On Wednesday, 11 April 2018 at 22:13:33 UTC, Sjoerd Nijboer wrote:
> On Wednesday, 11 April 2018 at 21:29:27 UTC, Alex wrote:
>> I would say, alias template parameter is your friend.
>> https://dlang.org/spec/template.html#TemplateAliasParameter
>>
>> class SortedList(T, alias comparer)
>
> It works, thank you!
> But just to be shure, there's no way to have this more strongly typed in D so I can enforce that `comparer`is a funciton or delegate with a specific definition?


There is, with template constraints:

class SortedList(T, alias comparer) if(is(typeof(comparer(T.init) : int))
{
    //...
}
April 12, 2018
On Thursday, 12 April 2018 at 00:05:26 UTC, Nicholas Wilson wrote:
> There is, with template constraints:
>
> class SortedList(T, alias comparer)
>     if(is(typeof(comparer(T.init) : int))
> {
>     //...
> }

If the function is declared with explicit parameter types:
```
auto list = new SortedList!(Vector3, (Vector3 v) => v.y)();
```

Then the template guard can even have a full type definition:
```
class SortedList(T, alias comparer)
    if (is(typeof(comparer) :  int function(T)))
{
    //...
}
```
April 12, 2018
On Thursday, 12 April 2018 at 11:17:01 UTC, Laurent Tréguier wrote:
> If the function is declared with explicit parameter types:

There are cool things possible, if the param type is explicitly typed :)

´´´
import std.traits;

void main()
{
	auto list = new SortedList!((Vector3 v) => v.y)();
	list.foo(Vector3.init);
}

struct Vector3 { float x, y, z; }

class SortedList(alias comparer) if(is(ReturnType!comparer : float))
{
	alias T = Parameters!comparer[0];

	T[] array;
	
	auto foo(T t)
	{
		// do stuff
	}
}
´´´
April 12, 2018
On Thursday, 12 April 2018 at 11:53:21 UTC, Alex wrote:
> On Thursday, 12 April 2018 at 11:17:01 UTC, Laurent Tréguier wrote:
>> If the function is declared with explicit parameter types:
>
> There are cool things possible, if the param type is explicitly typed :)
>
> ´´´
> import std.traits;
>
> void main()
> {
> 	auto list = new SortedList!((Vector3 v) => v.y)();
> 	list.foo(Vector3.init);
> }
>
> struct Vector3 { float x, y, z; }
>
> class SortedList(alias comparer) if(is(ReturnType!comparer : float))
> {
> 	alias T = Parameters!comparer[0];
>
> 	T[] array;
> 	
> 	auto foo(T t)
> 	{
> 		// do stuff
> 	}
> }
> ´´´

Getting rid of redundancy. Now that's nice !