Jump to page: 1 2 3
Thread overview
why cant structs have base structs
Jun 24, 2004
Regan Heath
Jun 24, 2004
Norbert Nemec
Jun 24, 2004
Regan Heath
Jun 24, 2004
Daniel Horn
Jun 24, 2004
Norbert Nemec
Jun 24, 2004
Jan-Eric Duden
Jun 24, 2004
Norbert Nemec
Jun 24, 2004
Jan-Eric Duden
Jun 24, 2004
Daniel Horn
Jul 01, 2004
Walter
Jul 01, 2004
Ivan Senji
Jul 01, 2004
Regan Heath
Jul 02, 2004
Ivan Senji
Jul 02, 2004
Regan Heath
Jul 02, 2004
Ivan Senji
Jul 01, 2004
Regan Heath
Jul 02, 2004
Regan Heath
Jul 02, 2004
Derek Parnell
Jul 02, 2004
Regan Heath
Jun 24, 2004
Russ Lewis
Jun 24, 2004
Jan-Eric Duden
Jun 24, 2004
Matthew
Jul 01, 2004
Brian
Jul 01, 2004
Regan Heath
Jul 01, 2004
Regan Heath
June 24, 2004
This:

struct a {
}

struct b : a {
}

is not valid, the spec does not seem to allow it, why not?

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
June 24, 2004
Regan Heath wrote:

> This:
> 
> struct a {
> }
> 
> struct b : a {
> }
> 
> is not valid, the spec does not seem to allow it, why not?

My guess:

Structs cannot have virtual functions (adding that feature would mean overhead which should be avoided for structs)

Without virtual functions, the behavior of struct-inheritance would be strangely different from the behavior of class-inheritance, where every public function is implicitly virtual.

Furthermore: without polymorphism (which would require virtual functions) inheritance is just a matter of saving some typing. And for that, you can also use mixins.


June 24, 2004
On Thu, 24 Jun 2004 07:52:11 +0200, Norbert Nemec <Norbert.Nemec@gmx.de> wrote:
> Regan Heath wrote:
>
>> This:
>>
>> struct a {
>> }
>>
>> struct b : a {
>> }
>>
>> is not valid, the spec does not seem to allow it, why not?
>
> My guess:
>
> Structs cannot have virtual functions (adding that feature would mean
> overhead which should be avoided for structs)

Agreed.

> Without virtual functions, the behavior of struct-inheritance would be
> strangely different from the behavior of class-inheritance, where every
> public function is implicitly virtual.

Different, yes. Strange .. not so long as it's documented.

> Furthermore: without polymorphism (which would require virtual functions)
> inheritance is just a matter of saving some typing. And for that, you can
> also use mixins.

Ok. You've convinced me.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
June 24, 2004
Regan Heath wrote:
> On Thu, 24 Jun 2004 07:52:11 +0200, Norbert Nemec <Norbert.Nemec@gmx.de> wrote:
> 
>> Regan Heath wrote:
>>
>>> This:
>>>
>>> struct a {
>>> }
>>>
>>> struct b : a {
>>> }
>>>
>>> is not valid, the spec does not seem to allow it, why not?
>>
>>
>> My guess:
>>
>> Structs cannot have virtual functions (adding that feature would mean
>> overhead which should be avoided for structs)
> 
> 
> Agreed.
> 
>> Without virtual functions, the behavior of struct-inheritance would be
>> strangely different from the behavior of class-inheritance, where every
>> public function is implicitly virtual.
> 
> 
> Different, yes. Strange .. not so long as it's documented.
> 
>> Furthermore: without polymorphism (which would require virtual functions)
>> inheritance is just a matter of saving some typing. And for that, you can
>> also use mixins.
> 
> 
> Ok. You've convinced me.
> 
but what if you wanted to pass a SuperThing into a function that only took a thing and didn't want to use templates

struct Thing{
 float amt;
}
struct SuperThing :Thing {
  char[] name;
}

now it's not just a matter of saving typing, but actually having it do all the things you could with thing.
in C you'd use an anonymous union to accomplish this-- is that also possible in D?

struct Thing {
 float amt;
};

struct SuperThing {
 union {
   float amt;
   Thing thing;
 };
 char[] name;
};

> Regan
> 
June 24, 2004
Daniel Horn wrote:

>>> Furthermore: without polymorphism (which would require virtual functions) inheritance is just a matter of saving some typing. And for that, you can also use mixins.
>> 
>> 
>> Ok. You've convinced me.
>> 
> but what if you wanted to pass a SuperThing into a function that only took a thing and didn't want to use templates

That's just what I mean with "polymorphism" - as mentioned: polymorphism demands for virtual functions, and these mean overhead. If you want polymorphism, use classes. (There is no point in using polymorphism without handling the objects by reference, anyway.)

June 24, 2004
Norbert Nemec wrote:
> Daniel Horn wrote:
> 
> 
>>>>Furthermore: without polymorphism (which would require virtual
>>>>functions) inheritance is just a matter of saving some typing. And for
>>>>that, you can also use mixins.
>>>
>>>
>>>Ok. You've convinced me.
>>>
>>
>>but what if you wanted to pass a SuperThing into a function that only
>>took a thing and didn't want to use templates
> 
> 
> That's just what I mean with "polymorphism" - as mentioned: polymorphism
> demands for virtual functions, and these mean overhead. If you want
> polymorphism, use classes. (There is no point in using polymorphism without
> handling the objects by reference, anyway.)
> 
"polymorphism" does not demand for virtual functions by default.
in C++ i could do the following:
struct MyPolyStruct
{
	int	type;
};
struct A : public MyPolyStruct
{
	int	a;
}
struct C : public MyPolyStruct
{
	float	c[1000];
}

void	bla(MyPolyStruct* p)
{
	switch(p->type)
	{
	//do stuff
	}
}

I still need to do a cast to get the subclass data,
but this is a bit "type-safier" than doing this in D:

template  MyPolyType
{
	int	type;	
};
struct Base
{
	mixin MyPolyType;
}
struct A
{
	mixin MyPolyType;
	int	a;
}
struct C
{
	mixin MyPolyType;
	float	c[1000];
}

int	bla(void* p)  // need to use void ptr here
{
	switch((cast(Base)p).type)
	{
		//do stuff
	}
}

some times you need to do this stuff, f.e. when you implement functions that work on binary formats. Standard polymorphism doesn't help here at all.

Are there better solutions for doing this kind of stuff in D?
Note that using unions doesn't really help ( without having memory overhead):
struct MyPolyStruct
{
	int	type;
	union
	{
		int  a;
		float  c[1000];
	} 	data;
};

Jan-Eric
June 24, 2004
Daniel Horn wrote:
> struct Thing{
>  float amt;
> }
> struct SuperThing :Thing {
>   char[] name;
> }
> 
> now it's not just a matter of saving typing, but actually having it do all the things you could with thing.
> in C you'd use an anonymous union to accomplish this-- is that also possible in D?
> 
> struct Thing {
>  float amt;
> };
> 
> struct SuperThing {
>  union {
>    float amt;
>    Thing thing;
>  };
>  char[] name;
> };

What you code here should work...though I don't know why you wouldn't just include the Thing directly.  The union is unnecessary:

struct SuperThing {
  Thing thing;
  char[] name;
};



If you want to implement something that looks more like C++ inheritance, you can do it with properties:

struct SuperThing {
  Thing super;
  float amt() { return super.amt; }
  float amt(float f) { return super.amt = f; }
  char[] name;
};

You don't get implicit casting, but that's not too hard:

Thing* castThing(SuperThing* s) { return s.super; }

Likewise, you can even implement constructors and virtual functions by hand if you want; but you have to run the constructor by hand, and make sure it initialized the virtual functions allright:

struct Thing {
  struct {
    int delegate() foo;
  } vtbl;

  void Constructor() {
    this.vtbl.foo = &this.foo;
  }

  int foo() { ...do stuff... }

  float amt;
}

struct SuperThing {
  Thing super;
  float amt() { return super.amt; }
  float amt(float f) { return super.amt = f; }

  void Constructor() {
    super.Constructor();
    super.vtbl.foo = &this.foo;
  }

  int foo() { ...do stuff... }

  char[] name;
}

Thing thing1;  thing1.Constructor();
SuperThing thing2;  thing2.Constructor();

Thing *ptr1;
Thing *ptr2;

ptr1 = &thing1;
ptr2 = castThing(&thing2);

ptr1.vtbl.foo();	// runs Thing.foo()
ptr2.vtbl.foo();	// runs SuperThing.foo()

June 24, 2004
Russ Lewis wrote:

> Daniel Horn wrote:
> 
>> struct Thing{
>>  float amt;
>> }
>> struct SuperThing :Thing {
>>   char[] name;
>> }
>>
>> now it's not just a matter of saving typing, but actually having it do all the things you could with thing.
>> in C you'd use an anonymous union to accomplish this-- is that also possible in D?
>>
>> struct Thing {
>>  float amt;
>> };
>>
>> struct SuperThing {
>>  union {
>>    float amt;
>>    Thing thing;
>>  };
>>  char[] name;
>> };
> 
> 
> What you code here should work...though I don't know why you wouldn't just include the Thing directly.  The union is unnecessary:
> 
> struct SuperThing {
>   Thing thing;
>   char[] name;
> };
> 
> 
> 
> If you want to implement something that looks more like C++ inheritance, you can do it with properties:
> 
> struct SuperThing {
>   Thing super;
>   float amt() { return super.amt; }
>   float amt(float f) { return super.amt = f; }
>   char[] name;
> };
> 
> You don't get implicit casting, but that's not too hard:
> 
> Thing* castThing(SuperThing* s) { return s.super; }
> 
> Likewise, you can even implement constructors and virtual functions by hand if you want; but you have to run the constructor by hand, and make sure it initialized the virtual functions allright:
> 
> struct Thing {
>   struct {
>     int delegate() foo;
>   } vtbl;
> 
>   void Constructor() {
>     this.vtbl.foo = &this.foo;
>   }
> 
>   int foo() { ...do stuff... }
> 
>   float amt;
> }
> 
> struct SuperThing {
>   Thing super;
>   float amt() { return super.amt; }
>   float amt(float f) { return super.amt = f; }
> 
>   void Constructor() {
>     super.Constructor();
>     super.vtbl.foo = &this.foo;
>   }
> 
>   int foo() { ...do stuff... }
> 
>   char[] name;
> }
> 
> Thing thing1;  thing1.Constructor();
> SuperThing thing2;  thing2.Constructor();
> 
> Thing *ptr1;
> Thing *ptr2;
> 
> ptr1 = &thing1;
> ptr2 = castThing(&thing2);
> 
> ptr1.vtbl.foo();    // runs Thing.foo()
> ptr2.vtbl.foo();    // runs SuperThing.foo()
> 
that looks like a reasonable solution.
it's not too much work for doing this kind of rare stuff.
with mixins you can do this, too:
struct Thing
{
	// stuff
}:
template  BaseStruct
{
	Thing 	myThing;
	Thing*	castThing()
	{
		return &myThing;
	}
};

struct A
{
	mixin BaseStruct;
	int	stuffint;
};
June 24, 2004
Jan-Eric Duden wrote:
> Are there better solutions for doing this kind of stuff in D?

Use classes!

The only reason to use struct instead of class is, if you want value-semantics (as opposed to reference semantics which are the only available behaviour for classes in D)

Polymorphism is generally only possible when handling references. (Since the size of an inheriting class is not known, it cannot be passed by value)

Your C++ example uses a pointer to a struct. In D, you should simply use a class for that.

June 24, 2004
Norbert Nemec wrote:
> Jan-Eric Duden wrote:
> 
>>Are there better solutions for doing this kind of stuff in D?
> 
> 
> Use classes!
> 
> The only reason to use struct instead of class is, if you want
> value-semantics (as opposed to reference semantics which are the only
> available behaviour for classes in D)
> 
> Polymorphism is generally only possible when handling references. (Since the
> size of an inheriting class is not known, it cannot be passed by value)
> 
> Your C++ example uses a pointer to a struct. In D, you should simply use a
> class for that.
> 
You can't use classes in some cases. With classes you can't model an exact binary layout. With classes you have memory overhead that is too large in some cases.Custom allocators won't help all the time.

A small example: I have a file with 1,000,000 objects. all objects have the same size. I need to do some sorting and other stuff. the object size is 16 bytes. 16 MB is not too much for my memory requirements.
I allocate just one chunk of memory. read all the objects into that chunk. hold a struct pointer on that chunk. easy and efficient.
If I have to do that with class objects... I get gc overhead for 1 million objects, 1 million times a monitor, 1 million times a virtual function table pointer, ... 1 million new calls, 1 million read calls.
In that case structs a just better.

Jan-Eric
« First   ‹ Prev
1 2 3