D - template functions
- Sean Kelly (17/17) Feb 22 2004 One feature of D I haven't completely adjusted to is the need to
- Sam McCall (9/22) Feb 22 2004 Maybe foo('c') would even be easier to parse. (Having a template foo and...
- C (13/38) Feb 22 2004 That sounds good to me, though I really don't know what the fuss is abou...
- Sean Kelly (17/24) Feb 22 2004 Perhaps it's a hold-over from C++, but I like having a unified calling
- Sam McCall (12/20) Feb 22 2004 Collection!(Object) foo;
- Ben Hinkle (23/43) Feb 23 2004 My first try to investigate this was to use:
- Sean Kelly (5/8) Feb 23 2004 I think it's more an example of how the syntax can get complicated
- Ben Hinkle (9/18) Feb 23 2004 what
- Ben Hinkle (30/39) Feb 23 2004 what
- Sam McCall (8/11) Feb 23 2004 Nice, but this should be a member function. More specifically, there
- Ben Hinkle (7/18) Feb 23 2004 :-)
- Sam McCall (8/20) Feb 23 2004 Yeah, I was thinking of just being able to override
- Sean Kelly (7/13) Feb 23 2004 I'm considering using free-functions to return iterators much like
- Sam McCall (44/75) Feb 23 2004 You certainly shouldn't be able to do this. Java lets you cast T[] to
- Matthew (9/34) Feb 22 2004 That sounds good to me, though I really don't know what the fuss is abou...
One feature of D I haven't completely adjusted to is the need to explicitly specify each parameter of template methods. Would it be too complicated to allow template parameter discovery somewhat similar to how it works in C++? template foo( Ty ) { int foo( Ty val ) { return 1; } } int main() { int i = foo!(int)( 1 ); // A: current int j = foo!( 'c' ); // B: optional? } I'd like to be able to do something like in B. The obvious catch is that more complex templates involving classes and the like could make such discovery difficult to impossible. Comments? Sean
Feb 22 2004
Sean Kelly wrote:template foo( Ty ) { int foo( Ty val ) { return 1; } } int main() { int i = foo!(int)( 1 ); // A: current int j = foo!( 'c' ); // B: optional? }Maybe foo('c') would even be easier to parse. (Having a template foo and a function foo is a symbol conflict anyways).I'd like to be able to do something like in B. The obvious catch is that more complex templates involving classes and the like could make such discovery difficult to impossible. Comments?I'd be happy with limited discovery, as I posted about earlier (every type parameter must be the type of at least one parameter, no non-trivial overloading), in every other case you'd have to specify manually. This isn't ideal but it's so much better than what we've got now, and seems to be relatively simple to implement. Sam
Feb 22 2004
I'd be happy with limited discovery, as I posted about earlier (every =type parameter must be the type of at least one parameter, no =non-trivial overloading)That sounds good to me, though I really don't know what the fuss is abou= t = on having to specify type . Sure its nice ( type deduction ) but are yo= u = really all that lazy ? :P C On Mon, 23 Feb 2004 13:53:52 +1300, Sam McCall <tunah.d tunah.net> wrote= :Sean Kelly wrote:nd =template foo( Ty ) { int foo( Ty val ) { return 1; } } int main() { int i =3D foo!(int)( 1 ); // A: current int j =3D foo!( 'c' ); // B: optional? }Maybe foo('c') would even be easier to parse. (Having a template foo a=a function foo is a symbol conflict anyways).I'd like to be able to do something like in B. The obvious catch is ==that more complex templates involving classes and the like could make=such discovery difficult to impossible. Comments?I'd be happy with limited discovery, as I posted about earlier (every =type parameter must be the type of at least one parameter, no =non-trivial overloading), in every other case you'd have to specify =manually. This isn't ideal but it's so much better than what we've got==now, and seems to be relatively simple to implement. Sam-- = Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Feb 22 2004
C wrote:Perhaps it's a hold-over from C++, but I like having a unified calling convention for functions. Also, there are times when template parameters might be non-obvious to the caller, though I'll grant that in D this could be solved via nested templates. But I'm undecided about whether I'd like this in D, as the template declaration method is quite different from that in C++. I just thought of a way around explicit type specification. Referring to my original example, this is a working substitute for B: char c = 'c'; int j = foo!( typeof( c ) )( c ); This is ovbiously more verbose, but it does help avoid maintenance problems regarding explicitly specified types. I'll have to think some more about whether type discovery might allow for something that is difficult to accomplish without it. For some reason I thought I'd come up with an example but if I did it currently escapes me. SeanI'd be happy with limited discovery, as I posted about earlier (every type parameter must be the type of at least one parameter, no non-trivial overloading)That sounds good to me, though I really don't know what the fuss is about on having to specify type . Sure its nice ( type deduction ) but are you really all that lazy ? :P
Feb 22 2004
Collection!(Object) foo; Collection!(String) bar; foo.addAll!(MyCollection!(String))(bar); versus foo.addAll(bar); Personally find the first one moderately unwritable and perfectly unreadable ;)That sounds good to me, though I really don't know what the fuss is about on having to specify type . Sure its nice ( type deduction ) but are you really all that lazy ? :Pchar c = 'c'; int j = foo!( typeof( c ) )( c ); This is ovbiously more verbose, but it does help avoid maintenance problems regarding explicitly specified types.Yes, but it's ugly, you have to remember which variable corresponds to which type argument, which the compiler already knows about. If something mechanical like this can do the job, why should you actually have to type it? Sam
Feb 22 2004
"Sam McCall" <tunah.d tunah.net> wrote in message news:c1bqrm$2fvv$1 digitaldaemon.com...My first try to investigate this was to use: class Collection(T:Object) { void addAll(Collection!(Object) x) {} } and then hope that Collection!(String) could be implicitly cast to Collection!(Object) but it failed to compile the addAll declaration. This looks to me like a bug in class template syntax. So my second attempt was interface Collection { void addAll(Collection x); } class LinkedList(T): Collection { void addAll(Collection x){} } and this worked fine when called with Collection foo = new LinkedList!(String); Collection bar = new LinkedList!(String); foo.addAll(bar); So my first guess is that templates might not be the right way to do what you want to do. That doesn't mean there isn't a problem with templates but I'm not sure this is a great example.Collection!(Object) foo; Collection!(String) bar; foo.addAll!(MyCollection!(String))(bar); versus foo.addAll(bar); Personally find the first one moderately unwritable and perfectly unreadable ;)That sounds good to me, though I really don't know what the fuss is about on having to specify type . Sure its nice ( type deduction ) but are you really all that lazy ? :Pchar c = 'c'; int j = foo!( typeof( c ) )( c ); This is ovbiously more verbose, but it does help avoid maintenance problems regarding explicitly specified types.Yes, but it's ugly, you have to remember which variable corresponds to which type argument, which the compiler already knows about. If something mechanical like this can do the job, why should you actually have to type it? Sam
Feb 23 2004
Ben Hinkle wrote:So my first guess is that templates might not be the right way to do what you want to do. That doesn't mean there isn't a problem with templates but I'm not sure this is a great example.I think it's more an example of how the syntax can get complicated rather than being an example of something you'd probably want to do very often. Sean
Feb 23 2004
"Sean Kelly" <sean ffwd.cx> wrote in message news:c1derl$2bif$1 digitaldaemon.com...Ben Hinkle wrote:whatSo my first guess is that templates might not be the right way to doOver lunch I realized the reason for not using a straightforward interface is that it loses the contained type T. So I think his example is actually a good one for any generic, efficient add method from one container type to another. If you start making assumptions about the source or destination types then my posted code would be ok - but it wouldn't work well for the general case.you want to do. That doesn't mean there isn't a problem with templates but I'm not sure this is a great example.I think it's more an example of how the syntax can get complicated rather than being an example of something you'd probably want to do very often.Sean
Feb 23 2004
"Sean Kelly" <sean ffwd.cx> wrote in message news:c1derl$2bif$1 digitaldaemon.com...Ben Hinkle wrote:whatSo my first guess is that templates might not be the right way to doTake Two. Collections are just waay to much fun to putter around with :-) Here's an example that results in calls that look like TmixCollectionTypes!(Object,String).addAll(foo,bar); when you want to copy from one contained type to another. More details: interface Collection(T) { // a cheesy Collection T getItem(); void addItem(T x); } template TmixCollectionTypes(S,T) { void addAll(Collection!(S) x, Collection!(T) y) { x.addItem(y.getItem()); // you get the idea... } } class LinkedList(T): Collection!(T) { // a cheesy list T getItem() { return item; } void addItem(T x) { item=x; } T item; } class String {} int main(char[][] argv) { Collection!(Object) foo = new LinkedList!(Object); Collection!(String) bar = new LinkedList!(String); TmixCollectionTypes!(Object,String).addAll(foo,bar); return 0; }you want to do. That doesn't mean there isn't a problem with templates but I'm not sure this is a great example.I think it's more an example of how the syntax can get complicated rather than being an example of something you'd probably want to do very often. Sean
Feb 23 2004
Ben Hinkle wrote:Take Two. Collections are just waay to much fun to putter around with :-) Here's an example that results in calls that look like TmixCollectionTypes!(Object,String).addAll(foo,bar);Nice, but this should be a member function. More specifically, there might be a better way for some collections than add() one item at a time. I guess my problem with these solutions is I want templates to help me - I want to give my variables more descriptive types and in exchange I want better type checking. I don't want to care about templates until there's a problem. Sam
Feb 23 2004
"Sam McCall" <tunah.d tunah.net> wrote in message news:c1dm0t$2ob1$1 digitaldaemon.com...Ben Hinkle wrote::-)Take Two. Collections are just waay to much fun to putter around withNote it would have to be a static member function - see the section "Limitations" in the Templates doc. Virtual template member functions are mind-bending (at least to me) since there would have to be vtable slots for every possible template instantiation.Here's an example that results in calls that look like TmixCollectionTypes!(Object,String).addAll(foo,bar);Nice, but this should be a member function. More specifically, there might be a better way for some collections than add() one item at a time.I guess my problem with these solutions is I want templates to help me - I want to give my variables more descriptive types and in exchange I want better type checking. I don't want to care about templates until there's a problem. Sam
Feb 23 2004
Ben Hinkle wrote:Oh yeah :-\Note it would have to be a static member function - see the section "Limitations" in the Templates doc.Here's an example that results in calls that look like TmixCollectionTypes!(Object,String).addAll(foo,bar);Nice, but this should be a member function. More specifically, there might be a better way for some collections than add() one item at a time.Virtual template member functions are mind-bending (at least to me) since there would have to be vtable slots for every possible template instantiation.Yeah, I was thinking of just being able to override template foo!(A,B:C) { void foo(A a,B b); } with template foo!(D,E:C) { void foo(D d,E e); } but I'm sure it quickly gets too complicated. Sam
Feb 23 2004
Sam McCall wrote:Nice, but this should be a member function. More specifically, there might be a better way for some collections than add() one item at a time.In some cases this couldn't be a member function. Arrays, for example.I guess my problem with these solutions is I want templates to help me - I want to give my variables more descriptive types and in exchange I want better type checking. I don't want to care about templates until there's a problem.I'm considering using free-functions to return iterators much like begin, end, etc, as they exist in the C++ standard library. Not having to explicitly specify template arguments for these functions would be a nice perk, but I think it will work out either way. Sean
Feb 23 2004
You certainly shouldn't be able to do this. Java lets you cast T[] to S[] where T is a subclass of S, and the result is the possibility that t[0]=a; gives you a runtime exception, if t a T[] variable that points to an S[], and a is a T but not an S. As much as I'd like it to be most of the time, Foo!(S : T) is-not-a Foo!(T). In this case, this would break type checking by allowing you to add any Object. Of course it won't work for ints either.Collection!(Object) foo; Collection!(String) bar; foo.addAll!(MyCollection!(String))(bar); versus foo.addAll(bar); Personally find the first one moderately unwritable and perfectly unreadable ;)My first try to investigate this was to use: class Collection(T:Object) { void addAll(Collection!(Object) x) {} } and then hope that Collection!(String) could be implicitly cast to Collection!(Object) but it failed to compile the addAll declaration.So my first guess is that templates might not be the right way to do what you want to do. That doesn't mean there isn't a problem with templates but I'm not sure this is a great example.I'm basing this on Java, which (IMO and ignoring the runtime problems) seems to be pretty well done using templates. For the record, my ideal definition would be interface Collection(T) { template addAll(S:T) { void addAll(Collection!(S) c); } } class LinkedList(T) : Collection!(T) { template addAll(S:T) { void addAll(Collection!(S) c) { foreach(S s;c) add(s); } } } (Actually there'd be a List interface in between). I'm not sure if template addAll(S:T) or template addAll(S:T,Collection!(S)) or template addAll(Collection!(S:T)) are the most likely to ever be supported by deduction, but the syntax foo.addAll!(bar.T)(bar) isn't much better than foo.addAll!(typeof(bar))(bar) in terms of readability. On an unrelated note having a template around every templated function is awkward, can we have some sugar please? ;) It'd also make me less nervous about exactly how overriding works when it's inside a template.This looks to me like a bug in class template syntax. So my second attempt was interface Collection { void addAll(Collection x); } class LinkedList(T): Collection { void addAll(Collection x){} } and this worked fine when called with Collection foo = new LinkedList!(String); Collection bar = new LinkedList!(String); foo.addAll(bar);As you pointed out, this isn't useful, as you'd find when you come to implement it. void addAll(Collection x) { foreach(T item;x){ // WTF is T? add(item); } } Even if you decide collections only hold objects, it isn't typesafe. Sam
Feb 23 2004
It's not a question of sloth. It's about whether, and how easily, one can write generic code.I'd be happy with limited discovery, as I posted about earlier (every type parameter must be the type of at least one parameter, no non-trivial overloading)That sounds good to me, though I really don't know what the fuss is about on having to specify type . Sure its nice ( type deduction ) but are you really all that lazy ? :P C On Mon, 23 Feb 2004 13:53:52 +1300, Sam McCall <tunah.d tunah.net> wrote:Sean Kelly wrote:-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/template foo( Ty ) { int foo( Ty val ) { return 1; } } int main() { int i = foo!(int)( 1 ); // A: current int j = foo!( 'c' ); // B: optional? }Maybe foo('c') would even be easier to parse. (Having a template foo and a function foo is a symbol conflict anyways).I'd like to be able to do something like in B. The obvious catch is that more complex templates involving classes and the like could make such discovery difficult to impossible. Comments?I'd be happy with limited discovery, as I posted about earlier (every type parameter must be the type of at least one parameter, no non-trivial overloading), in every other case you'd have to specify manually. This isn't ideal but it's so much better than what we've got now, and seems to be relatively simple to implement. Sam
Feb 22 2004