www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to declare a template type as parameter to functions

reply "Domingo" <mingodad gmail.com> writes:
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 ?
Nov 03 2014
next sibling parent "Domingo" <mingodad gmail.com> writes:
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)
Nov 03 2014
prev sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
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.
Nov 03 2014
parent reply "Domingo" <mingodad gmail.com> writes:
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 ?
Nov 03 2014
next sibling parent "Domingo" <mingodad gmail.com> writes:
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 !
Nov 03 2014
prev sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
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
Nov 03 2014
parent reply "Domingo" <mingodad gmail.com> writes:
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 !
Nov 03 2014
parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
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)
Nov 03 2014
parent reply "Domingo" <mingodad gmail.com> writes:
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 !
Nov 03 2014
parent "Domingo" <mingodad gmail.com> writes:
Here is my pull request 
https://github.com/D-Programming-Language/dlang.org/pull/690

Please anyone feel free to improve it.

Cheers !
Nov 03 2014