www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template question

reply Michiel <nomail please.com> writes:
I'm not yet familiar enough with the template system to do this.

I wrote the following function:

----------------------------------------
Set!(T[0]) set(T ...)(T elements) {
    auto result = new Set!(T[0]);

    foreach (element; elements) {
        result.add(element);
    }

    return result;
}
----------------------------------------

This gives a nice set literal syntax with implicit type deduction.

auto x = set(4, 5, 6, 99);

But the user of the function should also have the option to use it like
this:

auto x = set!(int);

To create the empty set (that can hold int). How can I implement this?

Thanks!

PS: I would have liked to skip the type altogether for the empty set,
but the problem appears when you want to put something inside that set.
I've considered using a dummy type and to somehow construct the correct
set-type after the first insert, but it wouldn't be consistent with
normal sets and altogether too much trouble.

-- 
Michiel
Feb 22 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Michiel,

 I'm not yet familiar enough with the template system to do this.
 
 I wrote the following function:
 
 ----------------------------------------
 Set!(T[0]) set(T ...)(T elements) {
 auto result = new Set!(T[0]);
 foreach (element; elements) {
 result.add(element);
 }
 return result;
 }
 ----------------------------------------
 This gives a nice set literal syntax with implicit type deduction.
 
 auto x = set(4, 5, 6, 99);
 
 But the user of the function should also have the option to use it
 like this:
 
 auto x = set!(int);

would this work? auto x = Set!(int); it's not quite as clean but... If you don't like that you could try having set used as above take 2 things plus a tuple, then have a version of the template that takes one type and has function that take one or zero arguments Set!(T) set(T, U, V...)(T e1, U e2, V elements) {...} template set(T) { Set!(T) set(T e1) {...} Set!(T) set() {...} } again, not as clean but, it could work. I haven't tried this so it may not work.
Feb 22 2007
parent reply Michiel <nomail please.com> writes:
BCS wrote:

 would this work?
 
 auto x = Set!(int);
 
 it's not quite as clean but...

It would have to be: auto x = new Set!(int);
 If you don't like that
 you could try having set used as above take 2 things plus a tuple, then
 have a version of the template that takes one type and has function that
 take one or zero arguments
 
 Set!(T) set(T, U, V...)(T e1, U e2, V elements) {...}
 
 template set(T)
 {
 Set!(T) set(T e1) {...}
 Set!(T) set() {...}
 }
 
 again, not as clean but, it could work.
 
 I haven't tried this so it may not work.

I don't really care if the function implementation isn't very clean, as long as it's clean where set literals are used. That's what you want from a library. I'll try it out and get back to you. -- Michiel
Feb 22 2007
parent reply Michiel <nomail please.com> writes:
Michiel wrote:
 BCS wrote:
 
 would this work?

 auto x = Set!(int);

 it's not quite as clean but...

It would have to be: auto x = new Set!(int);
 If you don't like that
 you could try having set used as above take 2 things plus a tuple, then
 have a version of the template that takes one type and has function that
 take one or zero arguments

 Set!(T) set(T, U, V...)(T e1, U e2, V elements) {...}

 template set(T)
 {
 Set!(T) set(T e1) {...}
 Set!(T) set() {...}
 }

 again, not as clean but, it could work.

 I haven't tried this so it may not work.

I don't really care if the function implementation isn't very clean, as long as it's clean where set literals are used. That's what you want from a library. I'll try it out and get back to you.

Hm. No go. I implemented it like this: ----------------------------------------------- Set!(T) set(T, U, V ...)(T e1, U e2, V rest) { // line 287 auto result = new Set!(T); result.add(e1); result.add(e2); foreach (element; rest) { result.add(element); } return result; } template set(T) { Set!(T) set() { return new Set!(T); } Set!(T) set(T e1) { auto result = new Set!(T); result.add(e1); return result; } } ----------------------------------------------- But got this error: set.d(287): template tools.Set.set(T,U,V...) is not a function template It's because of the existence of the second template. I removed it and the first would work. I also tried to rewrite the last two functions like this: ----------------------------------------------- Set!(T) set(T)() { return new Set!(T); } Set!(T) set(T)(T e1) { // line 303 auto result = new Set!(T); result.add(e1); return result; } ----------------------------------------------- But got this error: set.d(303): template tools.Set.set(T) conflicts with tools.Set.set(T,U,V...) at set.d(287) Which is strange, because it shouldn't conflict at all. A bug in dmd, perhaps? Thanks for the suggestion, anyway! I hadn't thought of it. -- Michiel
Feb 22 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Michiel,

 Michiel wrote:
 

 
 Thanks for the suggestion, anyway! I hadn't thought of it.
 

How about this, it might work. template set(T, U...) { static if(U.length == 0) { Set!(T) set() { return new Set!(T); } Set!(T) set(T e1) { auto result = new Set!(T); result.add(e1); return result; } } else { Set!(T) set(T e1, U rest) { // line 287 auto result = new Set!(T); result.add(e1); foreach (element; rest) { result.add(element); } return result; } } }
Feb 22 2007
parent Michiel <nomail please.com> writes:
BCS wrote:

 How about this, it might work.

No, afraid not. set.d(312): template tools.Set.set(T,U...) is not a function template I don't think the compiler can recognize it as a function template if you put a static if in between the function and the template. I've tried this one before. -- Michiel
Feb 22 2007
prev sibling next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Michiel wrote:
 But the user of the function should also have the option to use it like
 this:
 
 auto x = set!(int);
 
 To create the empty set (that can hold int). How can I implement this?

What's wrong with "auto x = new Set!(int);"? It's how every other class type is instantiated. An alternative would be to make your set type a struct instead of a class, then you could just have "Set!(int) x;" declare an empty set. You'd have to be careful about the copying behavior though, structs are copied by value, not reference. But if the struct contained a reference/pointer to the actual data, it could work.
 PS: I would have liked to skip the type altogether for the empty set,
 but the problem appears when you want to put something inside that set.
 I've considered using a dummy type and to somehow construct the correct
 set-type after the first insert, but it wouldn't be consistent with
 normal sets and altogether too much trouble.

This would probably be a bad idea in a statically typed language. It could be made to work, but that would require you to specify the type whenever you wanted to extract an element from the set...
Feb 22 2007
parent Michiel <nomail please.com> writes:
Frits van Bommel wrote:

 But the user of the function should also have the option to use it like
 this:

 auto x = set!(int);

 To create the empty set (that can hold int). How can I implement this?

What's wrong with "auto x = new Set!(int);"? It's how every other class type is instantiated.

In this case I'm trying to create set literals. They're very pretty if you have at least one parameter. I just wanted the empty set to not be an exception to the syntax.
 An alternative would be to make your set type a struct instead of a
 class, then you could just have "Set!(int) x;" declare an empty set.
 You'd have to be careful about the copying behavior though, structs are
 copied by value, not reference. But if the struct contained a
 reference/pointer to the actual data, it could work.

Hm.. I'd rather use 'new' as an exception for the empty set than go through that, I think.
 PS: I would have liked to skip the type altogether for the empty set,
 but the problem appears when you want to put something inside that set.
 I've considered using a dummy type and to somehow construct the correct
 set-type after the first insert, but it wouldn't be consistent with
 normal sets and altogether too much trouble.

This would probably be a bad idea in a statically typed language. It could be made to work, but that would require you to specify the type whenever you wanted to extract an element from the set...

That way it would become like Java data structures before generics. :) I knew it wouldn't be a good idea the minute I thought of it. -- Michiel
Feb 22 2007
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Michiel wrote:
 I'm not yet familiar enough with the template system to do this.
 
 I wrote the following function:
 
 ----------------------------------------
 Set!(T[0]) set(T ...)(T elements) {
     auto result = new Set!(T[0]);
 
     foreach (element; elements) {
         result.add(element);
     }
 
     return result;
 }
 ----------------------------------------
 
 This gives a nice set literal syntax with implicit type deduction.
 
 auto x = set(4, 5, 6, 99);
 
 But the user of the function should also have the option to use it like
 this:
 
 auto x = set!(int);
 
 To create the empty set (that can hold int). How can I implement this?
 
 Thanks!

SetOf!(T) set(T...)(T elements) { auto result = new SetOf!(T); foreach( element ; elements ) result.add(element); return result; } template SetOf(T...) { static if( is( typeof(T[0]) ) ) alias Set!(typeof(T[0])) SetOf; else alias Set!(T[0]) SetOf; } Obviously, this only works if Set!(T) expects "T" to be an actual type. Note that I haven't tried the above. This should *theoretically* work since taking the type of a type makes no sense (hence, the is expression should fail), whilst taking the type of a value does. If it doesn't work, blame it on just having woken up :P
 PS: I would have liked to skip the type altogether for the empty set,
 but the problem appears when you want to put something inside that set.
 I've considered using a dummy type and to somehow construct the correct
 set-type after the first insert, but it wouldn't be consistent with
 normal sets and altogether too much trouble.

Bad idea; the more you can get fixed at compile-time, the better. For instance, std.boxer.Box can store any type you want. Putting things into a box is easy enough, auto x = box(42); But taking them back out is a bit ugly. auto y = unbox!(int)(x); The reason for this is that the compiler needs to know what the result type of "unbox" is at compile-time, so you need to tell it. -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Feb 22 2007
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Daniel Keep wrote:
 SetOf!(T) set(T...)(T elements)
 {
     auto result = new SetOf!(T);
 
     foreach( element ; elements )
         result.add(element);
 
     return result;
 }
 
 template SetOf(T...)
 {
     static if( is( typeof(T[0]) ) )
         alias Set!(typeof(T[0])) SetOf;
     else
         alias Set!(T[0]) SetOf;
 }
 
 Obviously, this only works if Set!(T) expects "T" to be an actual type.

(Note: I haven't actually tried that code) First I'd like to suggest also skip adding the first element if it was a type. Second, if your SetOf doesn't work you might also try removing the typeof from the condition and switching the two clauses. IIRC is(x) is also false for any x that isn't a type.
 Note that I haven't tried the above.  This should *theoretically* work
 since taking the type of a type makes no sense (hence, the is expression
 should fail), whilst taking the type of a value does.

I seem to remember typeof(myType) being the type aliased to myType. I don't know why, but I do seem to recall that being the case...
 If it doesn't work, blame it on just having woken up :P

Ditto, except in my case blame it on it being after midnight here :P.
Feb 22 2007