Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Choosing between classes and structs

A msdn article on C# named Choosing Between Classes and Structures gives the following advice:

Consider defining a structure instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.

Do not define a structure unless the type has all of the following characteristics:

It logically represents a single value, similar to primitive types

(integer, double, and so on).

It has an instance size smaller than 16 bytes.

It is immutable.

It will not have to be boxed frequently. 

If one or more of these conditions are not met, create a reference type instead of a structure. Failure to adhere to this guideline can negatively impact performance.

I wonder what the answer would be in the case of D. So far I've simply used structs in all cases where I didn't need polymorphism. I don't know if size is also a consideration. Or anything else.

like image 984
fwend Avatar asked Jul 30 '11 17:07

fwend


2 Answers

In D, there are a few key differences from C# that make it idiomatic to use struct more frequently:

  1. There's no autoboxing because the problems it solves are typically solved with templates.

  2. Right now, the garbage collector is less efficient.

  3. Pointers to structs work well in most cases if you want reference semantics. (The only major exception being that pointers to structs with overloaded arithmetic or indexing operators behave weirdly because the operations are treated as pointer arithmetic instead of calling operator overloads.) Furthermore, structs can easily be heap allocated using the new operator.

  4. Structs can have deterministic destructors (not finalizers), copy constructors, etc., so you can do similar kinds of magic with them as in C++.

I'd say a struct should be used anytime you don't need polymorphism and won't need it in the future and don't need reference semantics, or if you need deterministic destruction, copy construction, etc. If you need polymorphism then you definitely need to use a class.

If you don't need polymorphism but want reference semantics then either a pointer to a heap-allocated struct or a final class would work well. A final class is slightly nicer syntactically and doesn't run into weird corner cases when overloading arithmetic operators. A struct avoids a few bytes of overhead by not having a vtable or a monitor. If neither of these are important to you then it's just a matter of personal preference.

like image 135
dsimcha Avatar answered Sep 28 '22 19:09

dsimcha


I would say that that advice definitely does not apply to D.

Structs are value types. Classes are reference types. Structs are normally on the stack (though they can be on the heap and pointed to with pointers). Classes are on the heap. Structs have no inheritance or polymorphism. Classes have inheritance and polymorphism.

It is very common to use structs in D. I think that the general rule is that if something doesn't need to have polymorphism, it should be a struct. The primary reason to choose a class over a struct is because you want inheritance and polymorphism.

The second reason would be if it just makes more sense for the type to be a reference type (e.g. a container should probably be a class, since copying it every time that you pass it to a function wouldn't be good). Structs can have reference semantics, but it's just cleaner to use classes for that.

And lastly, if a type has a lot of data in it and you don't need to have a copy of it whenever you pass it to a function, then it would be more efficient to make it a class and only copy it when you actually need to (though you can choose to just always pass it by ref instead).

D's structs are definitely fancier than C#'s structs, since they have destructors and postblit constructors. There are also no autoboxing issues in D, since D uses templates (similar to C++, albeit much more powerful and much easier to use) rather than generics. And if you need a pointer to a struct, it's easy to do. So, I really don't think that the advice for C# applies to D.

It seems to me that the C# advice stems from two issues:

  1. The fact that structs are value types and thus have value semantics.
  2. The fact that structs in C# have to deal with autoboxing and must be very worried about the cost of copying.

Structs are also value types in D, but they're powerful enough to be able to have reference semantics if you want to, and the addition of postblit constructors and destructors makes them useful for far more than what you can do with structs in C#. And since D doesn't have autoboxing, the concerns about autoboxing don't apply to D. You still don't want your structs to be huge, since unless you pass by ref, they're going to be copied whenever you pass them to a function, but it's definitely not as large a concern as it is in C#. It's much more in line with C++ in that regard.

And the advice about immutability does not apply at all to D. D structs are frequently mutable, and it would be a big problem if they weren't. Ranges, for instance, are usually implemented as structs, and that wouldn't be possible if you couldn't mutate them.

So, no, I don't think that the C# advice really applies to D. The situation between the two languages is just too different. It would be better to think of D's structs as C++ classes which don't have any base classes and can't be derived from, since that's far closer to what they actually are than C#'s structs.

like image 22
Jonathan M Davis Avatar answered Sep 28 '22 18:09

Jonathan M Davis