www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - struct vs. class

reply Martin <m_dot_hinsch rug.nl> writes:
Inspired by the recent discussion about iterator structs/classes I wanted to
ask - what's the design rationale behind having both structs and classes? In
C++ the necessity was given by backwards compatibility but that doesn't apply
to D of course. 
The only principal differences I can see (I'm not a D programmer (yet), so
please correct me if I'm wrong) are a) that structs don't contain run-time meta
information (a pointer to a vtable or however that works) and b) that struct
variables are statically allocated as opposed to class variables which always
seem to be pointers into dynamic memory.
Somehow this looks really unorthogonal to me. Especially b) I find strange, can
somebody explain the reason for this?

cheers
Martin
May 28 2007
next sibling parent Gregor Richards <Richards codu.org> writes:
Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted to
ask - what's the design rationale behind having both structs and classes? In
C++ the necessity was given by backwards compatibility but that doesn't apply
to D of course. 
 The only principal differences I can see (I'm not a D programmer (yet), so
please correct me if I'm wrong) are a) that structs don't contain run-time meta
information (a pointer to a vtable or however that works) and b) that struct
variables are statically allocated as opposed to class variables which always
seem to be pointers into dynamic memory.
 Somehow this looks really unorthogonal to me. Especially b) I find strange,
can somebody explain the reason for this?
 
 cheers
 Martin
Firstly, your assertion about C++ is incorrect. C++ doesn't have both, classes are just structs that are private by default, structs are just classes that are public by default. A C struct like this: struct Foo { int a, b; } is 100% equivalent (and passable as) a C++ class like this: class Bar { public: int a, b; } Structs in D are very light-weight. A struct is just a conglomeration of data. Passing a struct which contains two ints is exactly like passing the two ints, but syntactically less gross. Functions defined within a struct are basically syntactic sugar around functions that are defined taking the struct as the first argument. Classes are properly object oriented: They have hierarchies, methods are virtual, etc. As such, they're (comparably to structs) heavyweight: They have classinfo, are allocated on the heap, method calls require looking in a vtable, etc. Your 'b' statement is incorrect. In both cases, the data is allocated where the struct/class is allocated. Just classes are usually on the heap, structs are generally on the stack. - Gregor Richards
May 28 2007
prev sibling next sibling parent reply Martin <m_dot_hinsch rug.nl> writes:
Gregor Richards Wrote:

 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted to
ask - what's the design rationale behind having both structs and classes? In
C++ the necessity was given by backwards compatibility but that doesn't apply
to D of course. 
 The only principal differences I can see (I'm not a D programmer (yet), so
please correct me if I'm wrong) are a) that structs don't contain run-time meta
information (a pointer to a vtable or however that works) and b) that struct
variables are statically allocated as opposed to class variables which always
seem to be pointers into dynamic memory.
 Somehow this looks really unorthogonal to me. Especially b) I find strange,
can somebody explain the reason for this?
 
 cheers
 Martin
Firstly, your assertion about C++ is incorrect. C++ doesn't have both, classes are just structs that are private by default, structs are just classes that are public by default.
Yes, I know that - still, formally they are two different things (albeit very similar).
 Structs in D are very light-weight. A struct is just a conglomeration of 
 data. Passing a struct which contains two ints is exactly like passing 
 the two ints, but syntactically less gross. Functions defined within a 
Isn't that the same as a tuple, then?
 struct are basically syntactic sugar around functions that are defined 
 taking the struct as the first argument.
Hmmm, but in principle the same holds for class functions. The only difference is that there is an additional lookup rule since they are virtual per default.
 Classes are properly object oriented: They have hierarchies, methods are 
 virtual, etc. As such, they're (comparably to structs) heavyweight: They 
 have classinfo, are allocated on the heap, method calls require looking 
 in a vtable, etc.
 
There is no reason why structs couldn't have hierarchies as well.
 Your 'b' statement is incorrect. In both cases, the data is allocated 
 where the struct/class is allocated. Just classes are usually on the 
 heap, structs are generally on the stack.
 
Oh, then I got that wrong. I thought there was no way in D to create a class variable on the stack. Anyways, my point is that really the only *necessary* difference between structs and classes is that the latter can have run-time type information and virtual functions. Everything else is just convenient syntactical sugar for which there is no technical reason to not add it to structs as well. And if that's the case I start to wonder if it's not possible to unify the two concepts somehow. cheers Martin
May 28 2007
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 28 May 2007 17:36:51 -0400, Martin wrote:

 Anyways, my point is that really the only *necessary* difference
 between structs and classes is that the latter can have run-time
 type information and virtual functions. Everything else is just
 convenient syntactical sugar for which there is no technical
 reason to not add it to structs as well.
 And if that's the case I start to wonder if it's not possible
 to unify the two concepts somehow.
They cannot and should not be 'unified' because their purpose is different. They serve different roles for the programmer. To quote the D documentation "Structs are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type." Class objects contain at least two hidden data members which mean that they cannot be used to 'paint over RAM', to give structure to some data. See the ABI section of the docs ... An object consists of: --------*------------------ offset | contents --------+------------------ 0 | pointer to vtable ptrsize | monitor In other words an 'empty' object takes up 8 bytes (on a 32-bit machine) and an empty struct takes up zero bytes. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
May 28 2007
parent reply Martin <m_dot_hinsch rug.nl> writes:
Derek Parnell Wrote:

 On Mon, 28 May 2007 17:36:51 -0400, Martin wrote:
 
 Anyways, my point is that really the only *necessary* difference
 between structs and classes is that the latter can have run-time
 type information and virtual functions. Everything else is just
 convenient syntactical sugar for which there is no technical
 reason to not add it to structs as well.
 And if that's the case I start to wonder if it's not possible
 to unify the two concepts somehow.
They cannot and should not be 'unified' because their purpose is different. They serve different roles for the programmer. To quote the D documentation "Structs are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type." Class objects contain at least two hidden data members which mean that they cannot be used to 'paint over RAM', to give structure to some data. See the ABI section of the docs ... An object consists of: --------*------------------ offset | contents --------+------------------ 0 | pointer to vtable ptrsize | monitor In other words an 'empty' object takes up 8 bytes (on a 32-bit machine) and an empty struct takes up zero bytes. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
I know, but the differences between structs and classes go far beyond that. In my opinion that wouldn't be necessary. Or put the other way around I think it would be much more elegant (and make D easier to learn) to have aggregate types, RTTI and value/reference semantics as three orthogonal concepts. C++ does that by using virtual vs. the default and pointers/references vs. values with all the associated problems but there might be a cleaner and nicer way without having to give up the flexibility.
May 29 2007
parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
Martin wrote:
 C++ does that by using virtual vs. the
 default and pointers/references vs. values with all the associated
 problems but there might be a cleaner and nicer way without having to
 give up the flexibility.
That is why C++ sucks. I actually like the D solution .. specially having used Java before .. a language with NOTHING other than classes!! and C++ .. a language without "real" classes. D has the best "in the middle" solution.
May 29 2007
prev sibling next sibling parent reply Mike Parker <aldacron71 yahoo.com> writes:
Martin wrote:

 
 There is no reason why structs couldn't have hierarchies as well.
 
 Your 'b' statement is incorrect. In both cases, the data is allocated 
 where the struct/class is allocated. Just classes are usually on the 
 heap, structs are generally on the stack.
Oh, then I got that wrong. I thought there was no way in D to create a class variable on the stack. Anyways, my point is that really the only *necessary* difference between structs and classes is that the latter can have run-time type information and virtual functions. Everything else is just convenient syntactical sugar for which there is no technical reason to not add it to structs as well. And if that's the case I start to wonder if it's not possible to unify the two concepts somehow.
When you want POD (plain old data) objects, with or without methods to manipulate them, it is nice to not have the overhead associated with classes. It also would be a bit cumbersome to interface with C code if structs had all of the class overhead.
May 28 2007
parent janderson <askme me.com> writes:
Mike Parker wrote:
 Martin wrote:
 
 There is no reason why structs couldn't have hierarchies as well.

 Your 'b' statement is incorrect. In both cases, the data is allocated 
 where the struct/class is allocated. Just classes are usually on the 
 heap, structs are generally on the stack.
Oh, then I got that wrong. I thought there was no way in D to create a class variable on the stack. Anyways, my point is that really the only *necessary* difference between structs and classes is that the latter can have run-time type information and virtual functions. Everything else is just convenient syntactical sugar for which there is no technical reason to not add it to structs as well. And if that's the case I start to wonder if it's not possible to unify the two concepts somehow.
When you want POD (plain old data) objects, with or without methods to manipulate them, it is nice to not have the overhead associated with classes. It also would be a bit cumbersome to interface with C code if structs had all of the class overhead.
In c++ if you define a class without any virtual it effectively becomes a D struct, without the overhead. D takes this one step further I guess and allows the user enforce no virtuals. (Of course the other difference is that classes are passed by reference in D).
May 28 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Martin wrote:
 Gregor Richards Wrote:
 
 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted to
ask - what's the design rationale behind having both structs and classes? In
C++ the necessity was given by backwards compatibility but that doesn't apply
to D of course. 
 The only principal differences I can see (I'm not a D programmer (yet), so
please correct me if I'm wrong) are a) that structs don't contain run-time meta
information (a pointer to a vtable or however that works) and b) that struct
variables are statically allocated as opposed to class variables which always
seem to be pointers into dynamic memory.
 Somehow this looks really unorthogonal to me. Especially b) I find strange,
can somebody explain the reason for this?

 cheers
 Martin
Firstly, your assertion about C++ is incorrect. C++ doesn't have both, classes are just structs that are private by default, structs are just classes that are public by default.
Yes, I know that - still, formally they are two different things (albeit very similar).
And you can tell they're considered different things by the annoying fact that if you forward declare a type with the wrong one, the C++ compiler will generate an error. ----- class Foobulator; inline void function(Foobulator& fref) { . . . } ----- struct Foobulator { . . . }; ----- ==> Error Foobulator was declared as a class now it's a struct. grrr. I don't care which it is Mr. silly compiler! And you shouldn't either! All you need to know is that I can make a pointer to the darned thing! --bb
May 29 2007
parent reply James Dennett <jdennett acm.org> writes:
Bill Baxter wrote:
 Martin wrote:
 Gregor Richards Wrote:

 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I
 wanted to ask - what's the design rationale behind having both
 structs and classes? In C++ the necessity was given by backwards
 compatibility but that doesn't apply to D of course. The only
 principal differences I can see (I'm not a D programmer (yet), so
 please correct me if I'm wrong) are a) that structs don't contain
 run-time meta information (a pointer to a vtable or however that
 works) and b) that struct variables are statically allocated as
 opposed to class variables which always seem to be pointers into
 dynamic memory.
 Somehow this looks really unorthogonal to me. Especially b) I find
 strange, can somebody explain the reason for this?

 cheers
 Martin
Firstly, your assertion about C++ is incorrect. C++ doesn't have both, classes are just structs that are private by default, structs are just classes that are public by default.
Yes, I know that - still, formally they are two different things (albeit very similar).
And you can tell they're considered different things by the annoying fact that if you forward declare a type with the wrong one, the C++ compiler will generate an error.
(No, but a non-C++ compiler might...)
 -----
    class Foobulator;
 
    inline void function(Foobulator& fref) {
       . . .
    }
 -----
    struct Foobulator {
       . . .
    };
 -----
 ==> Error Foobulator was declared as a class now it's a struct.
 
 grrr.  I don't care which it is Mr. silly compiler!  And you shouldn't
 either!  All you need to know is that I can make a pointer to the darned
 thing!
I know of only one compiler which fails to compile that, and it's a bug. It's perfectly valid C++ code, and has been for a long, long time. class Foobulator; is *exactly* equivalent to struct Foobulator; in standard C++. (Note the semi-colons on there, making these non-definitions.) -- James
May 29 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
James Dennett wrote:
 Bill Baxter wrote:
 Martin wrote:
 Gregor Richards Wrote:

 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I
 wanted to ask - what's the design rationale behind having both
 structs and classes? In C++ the necessity was given by backwards
 compatibility but that doesn't apply to D of course. The only
 principal differences I can see (I'm not a D programmer (yet), so
 please correct me if I'm wrong) are a) that structs don't contain
 run-time meta information (a pointer to a vtable or however that
 works) and b) that struct variables are statically allocated as
 opposed to class variables which always seem to be pointers into
 dynamic memory.
 Somehow this looks really unorthogonal to me. Especially b) I find
 strange, can somebody explain the reason for this?

 cheers
 Martin
Firstly, your assertion about C++ is incorrect. C++ doesn't have both, classes are just structs that are private by default, structs are just classes that are public by default.
Yes, I know that - still, formally they are two different things (albeit very similar).
And you can tell they're considered different things by the annoying fact that if you forward declare a type with the wrong one, the C++ compiler will generate an error.
(No, but a non-C++ compiler might...)
 -----
    class Foobulator;

    inline void function(Foobulator& fref) {
       . . .
    }
 -----
    struct Foobulator {
       . . .
    };
 -----
 ==> Error Foobulator was declared as a class now it's a struct.

 grrr.  I don't care which it is Mr. silly compiler!  And you shouldn't
 either!  All you need to know is that I can make a pointer to the darned
 thing!
I know of only one compiler which fails to compile that, and it's a bug. It's perfectly valid C++ code, and has been for a long, long time.
Hmm. Would that compiler be Microsoft Visual C++ 6.0?
 class Foobulator;
 
 is *exactly* equivalent to
 
 struct Foobulator;
 
 in standard C++.  (Note the semi-colons on there, making
 these non-definitions.)
Hey, you're right! I just tried it out in gcc. Works fine. And works for MSVC.NET 2003 too. And DMC too! Imagine that. I'll go sit in a corner now. --bb
May 29 2007
parent James Dennett <jdennett acm.org> writes:
Bill Baxter wrote:
 James Dennett wrote:
 Bill Baxter wrote:
 Martin wrote:
 Gregor Richards Wrote:

 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I
 wanted to ask - what's the design rationale behind having both
 structs and classes? In C++ the necessity was given by backwards
 compatibility but that doesn't apply to D of course. The only
 principal differences I can see (I'm not a D programmer (yet), so
 please correct me if I'm wrong) are a) that structs don't contain
 run-time meta information (a pointer to a vtable or however that
 works) and b) that struct variables are statically allocated as
 opposed to class variables which always seem to be pointers into
 dynamic memory.
 Somehow this looks really unorthogonal to me. Especially b) I find
 strange, can somebody explain the reason for this?

 cheers
 Martin
Firstly, your assertion about C++ is incorrect. C++ doesn't have both, classes are just structs that are private by default, structs are just classes that are public by default.
Yes, I know that - still, formally they are two different things (albeit very similar).
And you can tell they're considered different things by the annoying fact that if you forward declare a type with the wrong one, the C++ compiler will generate an error.
(No, but a non-C++ compiler might...)
 -----
    class Foobulator;

    inline void function(Foobulator& fref) {
       . . .
    }
 -----
    struct Foobulator {
       . . .
    };
 -----
 ==> Error Foobulator was declared as a class now it's a struct.

 grrr.  I don't care which it is Mr. silly compiler!  And you shouldn't
 either!  All you need to know is that I can make a pointer to the darned
 thing!
I know of only one compiler which fails to compile that, and it's a bug. It's perfectly valid C++ code, and has been for a long, long time.
Hmm. Would that compiler be Microsoft Visual C++ 6.0?
You named that tune in one.
 class Foobulator;

 is *exactly* equivalent to

 struct Foobulator;

 in standard C++.  (Note the semi-colons on there, making
 these non-definitions.)
Hey, you're right! I just tried it out in gcc. Works fine. And works for MSVC.NET 2003 too. And DMC too! Imagine that. I'll go sit in a corner now.
This corner's taken, I banished myself here after posting something naive on a SQLite mailing list earlier... -- James
May 29 2007
prev sibling parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted
 to ask - what's the design rationale behind having both structs and classes?
 [...]
The most important difference is that structs have value semantics and classes have reference semantics. There are very good reasons to have both, and unifying them would be as wrong as taking away pointers or taking away stack objects. Dave
May 28 2007
parent reply Martin <m_dot_hinsch rug.nl> writes:
David B. Held Wrote:

 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted
 to ask - what's the design rationale behind having both structs and classes?
 [...]
The most important difference is that structs have value semantics and classes have reference semantics. There are very good reasons to have both, and unifying them would be as wrong as taking away pointers or taking away stack objects.
I totally agree that both are needed, but is it necessary to tie the difference to the difference between structs and classes? It would be nice if I could decide on the spot (i.e. when declaring a variable) in which way to use my type.
May 29 2007
parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Martin wrote:
 David B. Held Wrote:
 
 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted
 to ask - what's the design rationale behind having both structs and classes?
 [...]
The most important difference is that structs have value semantics and classes have reference semantics. There are very good reasons to have both, and unifying them would be as wrong as taking away pointers or taking away stack objects.
I totally agree that both are needed, but is it necessary to tie the difference to the difference between structs and classes? It would be nice if I could decide on the spot (i.e. when declaring a variable) in which way to use my type.
Unfortunately, you can't decide "on the spot" whether to use polymorphism or dynamic dispatch (nor can you make this choice on a per-instance basis in any other language I know of). The best you can do is get reference semantics for your structs by using 'ref'. But you will never get exact value semantics for classes because that could lead to slicing, which is why classes/structs in C++ are dangerous. However, you can simulate polymorphic value types by creating invariant classes. If you want to create both struct and class versions of your type and select them on a per-instance basis, you can create a template, but that doesn't make a whole lot of sense to me, so I'm not sure when or why you would do that. Dave
May 29 2007
parent reply Martin <m_dot_hinsch rug.nl> writes:
David B. Held Wrote:

 Martin wrote:
 David B. Held Wrote:
 
 Martin wrote:
 Inspired by the recent discussion about iterator structs/classes I wanted
 to ask - what's the design rationale behind having both structs and classes?
 [...]
The most important difference is that structs have value semantics and classes have reference semantics. There are very good reasons to have both, and unifying them would be as wrong as taking away pointers or taking away stack objects.
I totally agree that both are needed, but is it necessary to tie the difference to the difference between structs and classes? It would be nice if I could decide on the spot (i.e. when declaring a variable) in which way to use my type.
Unfortunately, you can't decide "on the spot" whether to use polymorphism or dynamic dispatch (nor can you make this choice on a per-instance basis in any other language I know of). The best you can do is get reference semantics for your structs by using 'ref'. But you will never get exact value semantics for classes because that could lead to slicing, which is why classes/structs in C++ are dangerous. However, you can simulate polymorphic value types by creating invariant classes. If you want to create both struct and class versions of your type and select them on a per-instance basis, you can create a template, but that doesn't make a whole lot of sense to me, so I'm not sure when or why you would do that. Dave
But if I understand it correctly the only points where problems can occur are in casts. This means that it should be possible to implement safeguards since for a value the type has to be known at compile time anyways whereas a reference will have RTTI. In both cases it's possible (either for the compiler or the run-time) to determine whether the cast is valid. The only reason why C++ fails miserably in this is that per default it just doesn't care about run-time stuff so every check for validity is up to the (potentially lazy) programmer. In D it would be perfectly possible to make a hybrid reference/value system failsafe. So, you could take a struct value and convert it into a class reference (probably by internally creating an object and filling it with values from the struct) and vice versa. Of course you wouldn't call it struct and class but just values and references of the same type. Note that there would be no reason to abandon the PODness of structs, when making a struct value from a class reference you'd just abandon the meta-info. I think that would simplify matters considerably. I might be totally off here but from what I've read in the docs and on the mailing list it looked to me as if the implementations of structs and classes in the compiler are at least to some degree a parallel effort. In any case, from the user's perspective I find the differences and the resulting restrictions on structs quite unintuitive and arbitrary.
May 29 2007
parent "David B. Held" <dheld codelogicconsulting.com> writes:
Martin wrote:
 [...]
 But if I understand it correctly the only points where problems can occur
 are in casts. This means that it should be possible to implement safeguards
 since for a value the type has to be known at compile time anyways whereas
 a reference will have RTTI.
 [...]
I guess my problem is lack of motivation. I'm just not seeing the use cases you are, so I don't see this part of the design space as lacking. Can you show us where you would like to use this feature and how it is better than the way things are now? Dave
May 29 2007