www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template Question

reply Mike Parker <aldacron71 yahoo.com> writes:
I've not worked much with templates in any language beyond the basics. 
Right now, I've got a problem that I've solved, but for which I'm 
looking a different solution.

What I have is a templated interface like so:

interface Foo(T)
{
     void init(T);
     void term();
     void blah();
     void bleh();
}

Then I have a Templated manager class intended to work with differently 
parameterized Foos:

class Manager(U)
{
     ...
}

The issue is that I want to make sure that Manager is instantiated with 
Foos without it knowing what the T in Foo is. This obviously doesn't work:

class Manager(U : Foo)
{
}

One way to solve the problem is to de-templatize Foo and create a new 
interface like so:

interface FooInit
{
}

interface Foo
{
    void init(FooInit fi);
}

I don't like that too much, though, since the parameters will always be 
PODs, so I'd prefer to use structs and not classes for them. The 
solution I've come up with, based on my limited knowledge, is to check 
that the parameter U for the manager implements all of the functions 
required by the Foo interface:

class Manager(U)
{
     static this()
     {
         static if(!is(typeof(&U.init)) && !is(typeof(&U.term))
                   && !is(typeof(&U.blah)) & !is(typeof(&U.bleh)));
     }
}

This works fine for my purposes, even though it allows any type that 
implements these methods, regardless of whether or not it implements Foo.

I'm curious if there is another way to do this, particularly some way to 
make sure that Manager only accepts Foo implementations without knowing 
how they are parameterized.
Apr 13 2008
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Mike Parker wrote:
 I've not worked much with templates in any language beyond the basics. 
 Right now, I've got a problem that I've solved, but for which I'm 
 looking a different solution.
 
 What I have is a templated interface like so:
 
 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }
 
 Then I have a Templated manager class intended to work with differently 
 parameterized Foos:
 
 class Manager(U)
 {
     ...
 }
 
 The issue is that I want to make sure that Manager is instantiated with 
 Foos without it knowing what the T in Foo is. This obviously doesn't work:
 
 class Manager(U : Foo)
 {
 }

I think there is a variation of that which is supposed to work: class Manager(U : Foo!(T), T) { } I'm not sure if it does in practice or not, though. --bb
Apr 13 2008
parent reply Mike Parker <aldacron71 yahoo.com> writes:
Bill Baxter wrote:
 Mike Parker wrote:
 I've not worked much with templates in any language beyond the basics. 
 Right now, I've got a problem that I've solved, but for which I'm 
 looking a different solution.

 What I have is a templated interface like so:

 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }

 Then I have a Templated manager class intended to work with 
 differently parameterized Foos:

 class Manager(U)
 {
     ...
 }

 The issue is that I want to make sure that Manager is instantiated 
 with Foos without it knowing what the T in Foo is. This obviously 
 doesn't work:

 class Manager(U : Foo)
 {
 }

I think there is a variation of that which is supposed to work: class Manager(U : Foo!(T), T) { } I'm not sure if it does in practice or not, though.

Unfortunately, it doesn't.
Apr 14 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 I've not worked much with templates in any language beyond the 
 basics. Right now, I've got a problem that I've solved, but for which 
 I'm looking a different solution.

 What I have is a templated interface like so:

 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }

 Then I have a Templated manager class intended to work with 
 differently parameterized Foos:

 class Manager(U)
 {
     ...
 }

 The issue is that I want to make sure that Manager is instantiated 
 with Foos without it knowing what the T in Foo is. This obviously 
 doesn't work:

 class Manager(U : Foo)
 {
 }

I think there is a variation of that which is supposed to work: class Manager(U : Foo!(T), T) { } I'm not sure if it does in practice or not, though.

Unfortunately, it doesn't.

I keep forgetting you don't get any type deduction with class templates. So maybe would work if you are explicit about both arguments. But that kind of defeats the purpose. Yeh, so I guess you just have to settle for class Manager(U /* : Foo!(T) */) { static if (is(U T_ : Foo!(T_))) { alias T_ T; } else { static assert(false, "U must be a Foo!(T) for some T"); } } --bb
Apr 14 2008
parent reply Mike Parker <aldacron71 yahoo.com> writes:
Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 I've not worked much with templates in any language beyond the 
 basics. Right now, I've got a problem that I've solved, but for 
 which I'm looking a different solution.

 What I have is a templated interface like so:

 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }

 Then I have a Templated manager class intended to work with 
 differently parameterized Foos:

 class Manager(U)
 {
     ...
 }

 The issue is that I want to make sure that Manager is instantiated 
 with Foos without it knowing what the T in Foo is. This obviously 
 doesn't work:

 class Manager(U : Foo)
 {
 }

I think there is a variation of that which is supposed to work: class Manager(U : Foo!(T), T) { } I'm not sure if it does in practice or not, though.

Unfortunately, it doesn't.

I keep forgetting you don't get any type deduction with class templates. So maybe would work if you are explicit about both arguments. But that kind of defeats the purpose. Yeh, so I guess you just have to settle for class Manager(U /* : Foo!(T) */) { static if (is(U T_ : Foo!(T_))) { alias T_ T; } else { static assert(false, "U must be a Foo!(T) for some T"); } } --bb

This is exactly what I was looking for. I don't understand it, but it works.
Apr 14 2008
parent reply Mike Parker <aldacron71 yahoo.com> writes:
Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 
 This is exactly what I was looking for. I don't understand it, but it 
 works.

Actually, it doesn't work.
Apr 14 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Mike Parker wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 This is exactly what I was looking for. I don't understand it, but it 
 works.

Actually, it doesn't work.

Yeh, it's a bug then. I'll file it. --bb
Apr 14 2008
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Mike Parker wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 This is exactly what I was looking for. I don't understand it, but it 
 works.

Actually, it doesn't work.

Ok, so in that case... I think you can put an alias for the type inside an interface, and use that to work around: interface Foo(T) { alias T TheType; void init(T); } ... static if ( is(U : Foo!(U.TheType)) ) { ... } That seems to work. --bb
Apr 14 2008
parent reply Mike Parker <aldacron71 yahoo.com> writes:
Bill Baxter wrote:
 Mike Parker wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 This is exactly what I was looking for. I don't understand it, but it 
 works.

Actually, it doesn't work.

Ok, so in that case... I think you can put an alias for the type inside an interface, and use that to work around: interface Foo(T) { alias T TheType; void init(T); } ... static if ( is(U : Foo!(U.TheType)) ) { ... } That seems to work.

Yes, this works. But, the static if evaluation never completes if U does not have TheType. It craps out with errors as soon as U.TheType is encountered rather than printing out the more friendly static assert.
Apr 14 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 This is exactly what I was looking for. I don't understand it, but 
 it works.

Actually, it doesn't work.

Ok, so in that case... I think you can put an alias for the type inside an interface, and use that to work around: interface Foo(T) { alias T TheType; void init(T); } ... static if ( is(U : Foo!(U.TheType)) ) { ... } That seems to work.

Yes, this works. But, the static if evaluation never completes if U does not have TheType. It craps out with errors as soon as U.TheType is encountered rather than printing out the more friendly static assert.

I don't understand. Can't you just make it static assert(is(U : Foo!(U.TheType))), "Use a Foo!() don't be a Foo! -- Mr. T"); --bb
Apr 14 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 This is exactly what I was looking for. I don't understand it, but 
 it works.

Actually, it doesn't work.

Ok, so in that case... I think you can put an alias for the type inside an interface, and use that to work around: interface Foo(T) { alias T TheType; void init(T); } ... static if ( is(U : Foo!(U.TheType)) ) { ... } That seems to work.

Yes, this works. But, the static if evaluation never completes if U does not have TheType. It craps out with errors as soon as U.TheType is encountered rather than printing out the more friendly static assert.

I don't understand. Can't you just make it static assert(is(U : Foo!(U.TheType))), "Use a Foo!() don't be a Foo! -- Mr. T");

Maybe you've found another bug? Expressions inside an "is" should never cause an error unless they're syntactically mal-formed, so if you're saying you're getting an actual error from the expression inside the static assert then that's a problem. But in that case I think you can work around with: static if (is(U.TheType)) { static assert(is(U : Foo!(U.TheType))), "Use a Foo!() don't be a Foo! -- Mr. T"); } else { static assert(false, "No .TheType so that can't be a Foo"); } --bb
Apr 14 2008
parent Mike Parker <aldacron71 yahoo.com> writes:
Bill Baxter wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:
 Bill Baxter wrote:
 Mike Parker wrote:




 This is exactly what I was looking for. I don't understand it, but 
 it works.

Actually, it doesn't work.

Ok, so in that case... I think you can put an alias for the type inside an interface, and use that to work around: interface Foo(T) { alias T TheType; void init(T); } ... static if ( is(U : Foo!(U.TheType)) ) { ... } That seems to work.

Yes, this works. But, the static if evaluation never completes if U does not have TheType. It craps out with errors as soon as U.TheType is encountered rather than printing out the more friendly static assert.

I don't understand. Can't you just make it static assert(is(U : Foo!(U.TheType))), "Use a Foo!() don't be a Foo! -- Mr. T");

Maybe you've found another bug? Expressions inside an "is" should never cause an error unless they're syntactically mal-formed, so if you're saying you're getting an actual error from the expression inside the static assert then that's a problem.

It errors out with the following: Error: no property 'TheType' for type 'MyType' However, I finally worked out a semi-solution using the traits module. ======================================================================= private bool isFoo(T)() { // make sure this T is a class so that the error // is reported from here and not from tango.core.Traits. static if(is(T == class)) { BaseTypeTupleOf!(T) tup; static if(tup.length > 0) { static if(typeof(tup[0]).stringof ~ "(T)" == Foo.stringof) return true; } } return false; } class FooManager(T) { static if(!isFoo!(T)) static assert(0, "Mr. T ain't no Foo, Foo!"); } ======================================================================= Each element of the tuple /should/ be iterated and compared with Foo.stringof. I was under the impression that foreach could be used at compile time, but using it here causes compilation to fail, saying that isFoo can't be run at compile time. Changing Foo to an abstract class and always checking the first element of the Tuple works, but it will still break of the class hierarchy goes deeper than one level.
Apr 15 2008
prev sibling parent reply BCS <BCS pathlink.com> writes:
Mike Parker wrote:
 I've not worked much with templates in any language beyond the basics. 
 Right now, I've got a problem that I've solved, but for which I'm 
 looking a different solution.
 
 What I have is a templated interface like so:
 
 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }
 

quick-n-dirty (and untested) interface FooBase{} interface Foo(T) : FooBase { void init(T); void term(); void blah(); void bleh(); } then throw this in somewhere: static assert(is(T:FooBase));
Apr 14 2008
next sibling parent Mike Parker <aldacron71 yahoo.com> writes:
BCS wrote:
 Mike Parker wrote:
 I've not worked much with templates in any language beyond the basics. 
 Right now, I've got a problem that I've solved, but for which I'm 
 looking a different solution.

 What I have is a templated interface like so:

 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }

quick-n-dirty (and untested) interface FooBase{} interface Foo(T) : FooBase { void init(T); void term(); void blah(); void bleh(); } then throw this in somewhere: static assert(is(T:FooBase));

Good idea. And it would be perfect if I could hide FooBase inside the module, but I recall reading somewhere that the compiler doesn't respect private class and interface declarations. And a quick test proves it.
Apr 14 2008
prev sibling parent Jakob <name domain.> writes:
BCS schrieb:
 Mike Parker wrote:
 I've not worked much with templates in any language beyond the basics. 
 Right now, I've got a problem that I've solved, but for which I'm 
 looking a different solution.

 What I have is a templated interface like so:

 interface Foo(T)
 {
     void init(T);
     void term();
     void blah();
     void bleh();
 }

quick-n-dirty (and untested) interface FooBase{} interface Foo(T) : FooBase { void init(T); void term(); void blah(); void bleh(); } then throw this in somewhere: static assert(is(T:FooBase));

While reading the posts of Mike and Bill above, i already wondered whether every Foo!(T) should be a subtype of Foo implicitly, so it would be possible to write "class Manager(U : Foo) {}" Just a fix idea. But if you can declare both Foo!(T) and Foo overloaded, FooBase could simply be renamed to Foo in the example above.
Apr 15 2008