tags:

views:

62

answers:

2
interface I1 { ... }
interface I2 { ... }
struct List(T) { ... }

How do I specialize my List to operate only on classes that implement both I1 and I2? One interface is easy:

struct List(T : I1)

Other languages. In C# it's:

struct List<T> where T : I1, I2

And in Java I'd say:

class List<T extends I1 & I2>

One catch: I don't want an if template constraint because I want reasonable auto-completion from a non-state-of-the-art IDEs. I think it'll be long before IDEs for D do things like reverse-engineering template constraints to deduce a list possible T's methods. And even if, that doesn't sound like cheap performance-wise.

+2  A: 

In D2, you can use template constraints (http://www.digitalmars.com/d/2.0/template.html#Constraint) and the is expression (http://www.digitalmars.com/d/2.0/expression.html#IsExpression).

struct List(T)
   if (is(T : I1) && is(T : I2))
{
   ...
}

Here, the is expressions checks whether T is implicitly convertible to I1 and I2 (which is only possible if T implements them).

JRM
I know;) But I clearly said that I don't want template constraints.
Tomek Sowiński
Whoops... sorry about that. That's what I get for not reading carefully. Given that constraint, the only thing I can think of is to define `interface I3 : I1, I2 {...}` and then limit List to I3. Not much better, though.
JRM
That's ok:) There's one problem with a dummy interface: `class Item : I1, I2`will get rejected. Scaling up, you'll end up with dummies in the number of all combinations of possible interfaces.
Tomek Sowiński
+2  A: 

If you don't want to constrain template by if statement, only way is this:

struct List(T : I1, U : I2 = T) {  }

that means that you can instantiate List with one or two arguments, if you instantiate only with one - List!(C), then the U will be by default assigned value C, and checked if it implements I2. You can then ignore parameter U in the struct. The problem with this method is that you instantiate the List with two parameters - List!(C1, C2)...

Here is version with if constraint, which doesn't have this problem:

struct List2(T) if ( is(T : I1) && is(T : I2)) {  }

There is no practical performance overhead in using if template constraint - or any compile time technique - if you are not calculating lot of data (like ct raytracer or look-up tables)

I would really suggest you to not limit your code to what the IDE supports - there sure will be many things that your IDE is not supporting well and you may find yourself having much less fun than using simple text editor with only sintax highlight, but with full potential of D.

Michal Minich
The first example with the default parameter is interesting, thanks.By "doesn't sound cheap" I didn't mean runtime perf but the IDE (if such clever one existed) to prompt me with a method list for T would have to evaluate the constraint, traverse the expression, recognize that they're both implicit conversion requirements, that there's an )
Tomek Sowiński
A static assert(is(T == U)) inside the template will stop the misuse case.
BCS