Thread overview
Template bug?
Jan 30, 2007
Artyom Shalkhakov
Jan 30, 2007
Artyom Shalkhakov
Jan 30, 2007
Frits van Bommel
January 30, 2007
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.
January 30, 2007
"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.


January 30, 2007
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?
January 30, 2007
"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.


January 30, 2007
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.
January 31, 2007
"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.