www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template bug?

reply Artyom Shalkhakov <artyom.sh gmail.ru> writes:
Hello everyone.

I have a problem regarding D templates.

This code doesn't work. I would like to know how do I get it up'n'running?

struct temp_t( type ) {
    void setOwner( type *newOwner ) {
        owner = newOwner;
    }

    type *getOwner() {
        return owner;
    }

    protected {
       temp_t *  head;
       temp_t *  next;
       temp_t *  prev;
       type *      owner;
    }
}

class testClass_t {
    this( int d ) {
        data = d;
        tst.setOwner( &this );
    }

    int                               data;
    temp_t!( testClass_t )    tst;
}

void foo() {
    testClass_t bar = new testClass_t( 0x1234 );

    // what is the difference between '==' and 'is'?
    assert( ( *bar ).getOwner == bar );  // doesn't work
}

Can anyone tell me what is wrong? Thanks in advance.

PS Excuse me for my English, as it's not my native language.
Jan 29 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Artyom Shalkhakov" <artyom.sh gmail.ru> wrote in message 
news:epmho3$282d$1 digitaldaemon.com...
 Hello everyone.

 I have a problem regarding D templates.

 This code doesn't work. I would like to know how do I get it up'n'running?

 struct temp_t( type ) {
    void setOwner( type *newOwner ) {
        owner = newOwner;
    }

    type *getOwner() {
        return owner;
    }

    protected {
       temp_t *  head;
       temp_t *  next;
       temp_t *  prev;
       type *      owner;
    }
 }

 class testClass_t {
    this( int d ) {
        data = d;
        tst.setOwner( &this );
    }

    int                               data;
    temp_t!( testClass_t )    tst;
 }

 void foo() {
    testClass_t bar = new testClass_t( 0x1234 );

    // what is the difference between '==' and 'is'?
    assert( ( *bar ).getOwner == bar );  // doesn't work
 }

There are a few things going wrong. One, when you write "tst.setOwner( &this );", this sets the owner to the address of a local variable. This is a Bad Thing. Remember that classes are reference types, so they are implicitly pointers. So instead of making your struct use pointers, just take all the *s out. struct temp_t( type ) { void setOwner( type newOwner ) { owner = newOwner; } type getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; type owner; } } Then in your class's constructor, use tst.setOwner( this ); Lastly, this line: assert( ( *bar ).getOwner == bar ); Doesn't even compile because (1) you cannot dereference bar because it's not a pointer, it's a reference, and (2) there is no .getOwner property for the testClass_t class. Instead, you should use: assert( bar.tst.getOwner is bar); And that brings me to my last point, the difference between 'is' and '=='. 'is' is used to see if two references (or pointers) point to the same location. '==' is used to see if two things are equal. If you have two class references, a and b, and you write a == b This is the same as writing a.opEquals(b) If a is null, this will get you a segfault. However, if you just want to see if a and b are pointing to the same instance, use a is b Which is what you want to do in your example.
Jan 29 2007
parent reply Artyom Shalkhakov <artyom.sh gmail.ru> writes:
Jarrett Billingsley Wrote:

 "Artyom Shalkhakov" <artyom.sh gmail.ru> wrote in message 
 news:epmho3$282d$1 digitaldaemon.com...
 Hello everyone.

 I have a problem regarding D templates.

 This code doesn't work. I would like to know how do I get it up'n'running?

 struct temp_t( type ) {
    void setOwner( type *newOwner ) {
        owner = newOwner;
    }

    type *getOwner() {
        return owner;
    }

    protected {
       temp_t *  head;
       temp_t *  next;
       temp_t *  prev;
       type *      owner;
    }
 }

 class testClass_t {
    this( int d ) {
        data = d;
        tst.setOwner( &this );
    }

    int                               data;
    temp_t!( testClass_t )    tst;
 }

 void foo() {
    testClass_t bar = new testClass_t( 0x1234 );

    // what is the difference between '==' and 'is'?
    assert( ( *bar ).getOwner == bar );  // doesn't work
 }

There are a few things going wrong. One, when you write "tst.setOwner( &this );", this sets the owner to the address of a local variable. This is a Bad Thing. Remember that classes are reference types, so they are implicitly pointers. So instead of making your struct use pointers, just take all the *s out. struct temp_t( type ) { void setOwner( type newOwner ) { owner = newOwner; } type getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; type owner; } } Then in your class's constructor, use tst.setOwner( this ); Lastly, this line: assert( ( *bar ).getOwner == bar ); Doesn't even compile because (1) you cannot dereference bar because it's not a pointer, it's a reference, and (2) there is no .getOwner property for the testClass_t class. Instead, you should use: assert( bar.tst.getOwner is bar); And that brings me to my last point, the difference between 'is' and '=='. 'is' is used to see if two references (or pointers) point to the same location. '==' is used to see if two things are equal. If you have two class references, a and b, and you write a == b This is the same as writing a.opEquals(b) If a is null, this will get you a segfault. However, if you just want to see if a and b are pointing to the same instance, use a is b Which is what you want to do in your example.

Thanks for your answer. Yes, it was my mistake to write it out like this:
assert( ( *bar ).getOwner == bar );

Well, this is my bug :) tst.setOwner( &this ); Okay, I've tried to use pointer to class because I intend to use this template for both structures and classes. How do I do that? Do I have to write template specialization?
Jan 29 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Artyom Shalkhakov" <artyom.sh gmail.ru> wrote in message 
news:epmlh5$2crr$1 digitaldaemon.com...

 Okay, I've tried to use pointer to class because I intend to use this 
 template for both structures and classes. How do I do that? Do I have to 
 write template specialization?

Yep. You can do something like: struct temp_t( type : Object ) { void setOwner( type newOwner ) { owner = newOwner; } type getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; type owner; } } struct temp_t( type ) { void setOwner( type *newOwner ) { owner = newOwner; } type *getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; type * owner; } } So it'll use the non-pointer version for classes (i.e. anything that derives from Object), and the pointer version for everything else.
Jan 30 2007
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Jarrett Billingsley wrote:
 "Artyom Shalkhakov" <artyom.sh gmail.ru> wrote in message 
 news:epmlh5$2crr$1 digitaldaemon.com...
 
 Okay, I've tried to use pointer to class because I intend to use this 
 template for both structures and classes. How do I do that? Do I have to 
 write template specialization?

Yep. You can do something like: struct temp_t( type : Object ) { void setOwner( type newOwner ) { owner = newOwner; } type getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; type owner; } } struct temp_t( type ) { void setOwner( type *newOwner ) { owner = newOwner; } type *getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; type * owner; } }

static if + is-expressions (and creative 'alias' usage) clean that up pretty well: ----- struct temp_t( type ) { static if(is(type == class)) alias type RefType; else alias type* RefType; void setOwner( RefType newOwner ) { owner = newOwner; } RefType getOwner() { return owner; } protected { temp_t * head; temp_t * next; temp_t * prev; RefType owner; } } ----- Code duplication is ugly.
Jan 30 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message 
news:epnmuo$n9t$2 digitaldaemon.com...

 static if + is-expressions (and creative 'alias' usage) clean that up 
 pretty well:
 -----
 struct temp_t( type ) {
     static if(is(type == class))
         alias type RefType;
     else
         alias type* RefType;

     void setOwner( RefType newOwner ) {
         owner = newOwner;
     }

     RefType getOwner() {
         return owner;
     }

     protected {
        temp_t *  head;
        temp_t *  next;
        temp_t *  prev;
        RefType   owner;
     }
 }

Ahh, I was thinking about static if but thought that doing it for each member would have been ugly.. never thought about using an aliased type.
Jan 30 2007