Thread overview
How to declare a template type as parameter to functions
Nov 03, 2014
Domingo
Nov 03, 2014
Domingo
Nov 03, 2014
H. S. Teoh
Nov 04, 2014
Domingo
Nov 04, 2014
Domingo
Nov 04, 2014
H. S. Teoh
Nov 04, 2014
Domingo
Nov 04, 2014
H. S. Teoh
Nov 04, 2014
Domingo
Nov 04, 2014
Domingo
November 03, 2014
Hello !

I could not find a clear way that show how to use template types as parameter to functions:

There is a general rule to do it ? On several examples when the return type comes from a template I saw the usage of "auto" where the compiler will deduce the correct type but when we need to pass that value as a parameter to a function how we declare then as parameter ?


//void dummFunction(type<Bson,Bson,Bson> "appender", type<forFromAuto> "another templated type")

void dummFunction(typeforFromAuto "appender", typeforFromAuto "another templated type")
{
}

auto as = appender!string();
auto an = appender!double();
auto an = appender!customType();
auto bd = collection.find().limit(2);

struct MongoCursor(Q = Bson, R = Bson, S = Bson);

auto bd2 = collection.find(Bson(["key": Bson(3)])).limit(2);
auto bd3 = collection.find(Bson(["key": Bson(3)]), ["fld":1, "data":1]).limit(2);

The above example is dummy example only imagine that you need to write a function accepting one of the several templated types returned on several parts of phobos and third party libraries like vibed.

Can someone give a general rule for this kind of problem ?
November 03, 2014
One of the problems I'm facing from vibed (but I'm asking a general rule to help here and in other similar cases):

protected void sendCollectionListAsDataArrayJson2(MongoCursor!(Bson,Bson,Bson) collection_list, HTTPServerResponse res)
{
	if(!collection_list.empty)
	{
		auto buf = appender!string();
		buf.put("{\"data\":[\n");
		int count = 0;
		foreach(doc; collection_list)
		{
			if(count++ > 0)
			{
				buf.put(",");
			}
			
			buf.put("[");
			buf.put(doc.toJson().toString());
			buf.put("]\n");
		}
		buf.put("]}\n");
		res.writeBody(buf.data, "application/json");
	}
}

-------
../../dLib/inhouse-code/vibed_common.d(313): Error: function vibed_common.BaseHttpHandler.sendCollectionListAsDataArrayJson2 (MongoCursor!(Bson, Bson, Bson) collection_list, HTTPServerResponse res) is not callable using argument types (MongoCursor!(Bson, Bson, typeof(null)), HTTPServerResponse)
../ApakauAdminCommon/vibed/geoips_mixin.d(38): Error: function vibed_common.BaseHttpHandler.sendCollectionListAsDataArrayJson2 (MongoCursor!(Bson, Bson, Bson) collection_list, HTTPServerResponse res) is not callable using argument types (MongoCursor!(Bson, Bson, int[string]), HTTPServerResponse)
../ApakauAdminCommon/vibed/geoips_mixin.d(50): Error: function vibed_common.BaseHttpHandler.sendCollectionListAsDataArrayJson2 (MongoCursor!(Bson, Bson, Bson) collection_list, HTTPServerResponse res) is not callable using argument types (MongoCursor!(Bson, Bson, int[string]), HTTPServerResponse)
November 03, 2014
On Mon, Nov 03, 2014 at 11:43:42PM +0000, Domingo via Digitalmars-d-learn wrote:
> Hello !
> 
> I could not find a clear way that show how to use template types as parameter to functions:
> 
> There is a general rule to do it ? On several examples when the return type comes from a template I saw the usage of "auto" where the compiler will deduce the correct type but when we need to pass that value as a parameter to a function how we declare then as parameter ?
> 
> 
> //void dummFunction(type<Bson,Bson,Bson> "appender", type<forFromAuto>
> "another templated type")
> 
> void dummFunction(typeforFromAuto "appender", typeforFromAuto "another
> templated type")
> {
> }

Use the typeof operator, for example:

	auto myfunc(...) {
		struct InternalType { ... }
		...
		return InternalType(...);
	}

	void anotherFunc(typeof(myfunc(...)) x) { ... }

	void main() {
		auto x = myfunc(...);
		anotherFunc(x);
	}

Using typeof() everywhere is ugly, though, so you could abstract it away
with an alias:

	auto myfunc(...) { ... }

	alias MyType = typeof(myfunc(...));

	void anotherFunc(MyType x) { ... }

	...

On the other hand, if anotherFunc() doesn't really need to know what exact type is passed, you could turn it into a template function:

	auto myfunc(...) { ... }

	// Now you can pass anything to anotherFunc:
	void anotherFunc(T)(T x) { ... }

But passing "anything" may cause problems, if anotherFunc expects x to have certain methods, but it's not guaranteed to have them:

	void anotherFunc(T)(T x) {
		...
		x.method(); // will fail if T is int, for example
		...
	}

In this case you can use a signature constraint to limit the scope of what anotherFunc will accept:

	auto myfunc(...) { ... }

	void anotherFunc(T)(T x)
		if (is(T.init.method())) // test that T has a method called "method"
	{
		...
		x.method();
		...
	}


T

-- 
Being able to learn is a great learning; being able to unlearn is a greater learning.
November 04, 2014
Thanks for the answer !

But then I can see that using D style templates everywhere will prevent write generic code and what seems to be an innocent function call will explode to bloated mass of code.

Like the "simple" function that I tried to write to not duplicate code is not worth because I'll need to write one for each type of MongoCursor:

1 - MongoCursor!(Bson, Bson, typeof(null))
2 - MongoCursor!(Bson, Bson, Bson)
3 - MongoCursor!(Bson, Bson, int[string])

protected void sendCollectionListAsDataArrayJson2(T)(T collection_list, HTTPServerResponse res)

What will be "T" on the function above ?
If I need to write one for each of then My intent of prevent duplicated code is dead.
The function only use code that should work on any combination of MongoCursor template.

To write less code I'll end up writing more code ?

Or are we missing something else here ?
November 04, 2014
Now I realize that what I said on the previous post is not correct.

Based on the proposed use of typeof/alias we will need something like this:


alias MongoCurosr3NUll = MongoCursor!(Bson, Bson, typeof(null));
alias MongoCursor3Bson = MongoCursor!(Bson, Bson, Bson);
alias MongoCursor3IntStr = MongoCursor!(Bson, Bson, int[string]);

then call my function like this:

sendCollectionListAsDataArrayJson2!MongoCurosr3NUll( MongoCurosr3NUllParam, res);

sendCollectionListAsDataArrayJson2!MongoCursor3Bson( MongoCursor3BsonParam, res);

sendCollectionListAsDataArrayJson2!MongoCursor3IntStr( MongoCursor3IntStrParam, res);


I do not think this way of writing code is "DRY" or easy to write/read/understand, it seems that D code will end up been a crypt one a la "perl" !!!

No offense here to perl but some write code style used on it.

!!!!! Please help here to make this clear for me and future D language users !!!!!!!

Cheers !
November 04, 2014
On Tue, Nov 04, 2014 at 12:29:54AM +0000, Domingo via Digitalmars-d-learn wrote: [...]
> Like the "simple" function that I tried to write to not duplicate code is not worth because I'll need to write one for each type of MongoCursor:
> 
> 1 - MongoCursor!(Bson, Bson, typeof(null))
> 2 - MongoCursor!(Bson, Bson, Bson)
> 3 - MongoCursor!(Bson, Bson, int[string])
> 
> protected void sendCollectionListAsDataArrayJson2(T)(T
> collection_list, HTTPServerResponse res)
> 
> What will be "T" on the function above ?

T is a placeholder identifier that can be any accepted type. For example:

	// Note: only one copy of func needs to be written
	void func(T)(T x) {
		writeln("%s", x);
	}

	void main() {
		func(1); // you can pass an int
		func("x"); // or a string
		func(1.0); // or a float

		struct S {}
		S s;
		func(s); // or a struct
	}


> If I need to write one for each of then My intent of prevent
> duplicated code is dead.
> The function only use code that should work on any combination of
> MongoCursor template.

That's exactly what you need a template function for. Instead of writing 15 copies of the function, one for each different MongoCursor type, you write only a single function that takes a generic parameter, for example:

	void sendCollection(T)(MongoCursor!(Bson, Bson, T) list,
		HttpRequest req)
	{
		...
	}

	...
	HttpRequest req;
	MongoCursor!(Bson, Bson, int) x1;
	MongoCursor!(Bson, Bson, float) x2;
	MongoCursor!(Bson, Bson, int[string]) x3;

	// N.B.: you can pass any matching type
	sendCollection(x1, req);
	sendCollection(x2, req);
	sendCollection(x3, req);

Of course, the foregoing assumes that only the last parameter of MongoCursor varies. If you need to take MongoCursor of *any* combination of parameters, you can use multiple template parameters, e.g.:

	// Now this will work with MongoCursor!(Bson, Bson,
	// int[string]), MongoCursor!(Json, Bson, Bson),
	// MongoCursor!(string, int, float), etc..
	void sendCollection(T,U,V)(MongoCursor!(T,U,V) list, ...) {
		...
	}


T

-- 
Those who don't understand D are condemned to reinvent it, poorly. -- Daniel N
November 04, 2014
Thanks again this second explanation now is easier to understand as general rule for this case and future ones that I'll face in the future.

I hope that this explanation would be added to the language reference where it explain functions:

http://dlang.org/function

With it there people will have a better understand right from the fundamental source of information.

Can someone add it there ?

Cheers !
November 04, 2014
On Tue, Nov 04, 2014 at 12:48:47AM +0000, Domingo via Digitalmars-d-learn wrote:
> Thanks again this second explanation now is easier to understand as general rule for this case and future ones that I'll face in the future.
> 
> I hope that this explanation would be added to the language reference where it explain functions:
> 
> http://dlang.org/function
> 
> With it there people will have a better understand right from the fundamental source of information.
> 
> Can someone add it there ?
[...]

Wow, I can't believe that page doesn't even *mention* template functions except in a single sentence!  Please file a bug on issues.dlang.org to improve the documentation of template functions.

In the meantime, the language reference really isn't the best source for learning the language; Ali's excellent D book is better:

	http://ddili.org/ders/d.en/templates.html

Andrei's book "The D Programming Language" is also highly recommended.


T

-- 
"Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next. -- (Stolen from the net)
November 04, 2014
Thanks again the bug issue is there at https://issues.dlang.org/show_bug.cgi?id=13677

But probably I should fork the repository and fix myself !
November 04, 2014
Here is my pull request https://github.com/D-Programming-Language/dlang.org/pull/690

Please anyone feel free to improve it.

Cheers !