Question

I've read a comparison of C# and Java and the first thing on the list is "Single-root (unified) type system".

Can you describe what a single-root (unified) type system means?

Was it helpful?

Solution

C# has a unified type system. All C# types, including primitive types such as int and double, inherit from a single root object type. Unlike class objects, these primitive types are value-types. They are not separately heap-allocated, and they are passed by value.

When a C# value type (such as a primitive int, or user-defined struct) is placed in a parametric collection, it is stored in a densely packed array with no pointers. This is possible because C# makes a custom parametric instantiation for each different parametric 'size' that is required. This means when you instantiate a C# List<int>, the underlying array list stores densely packed arrays of int.

Source: http://www.pin5i.com/showtopic-24376.html

Java also has several primitive types (int, long, double, byte, etc) - however, they are special in that they are not object-oriented and they could not have been defined using the language itself. They are value types, not heap allocated, and passed by value.

Source: Comparison of C# and Java - Unified type system (Wikipedia)

At the same time, Java also has object-oriented primitive "wrapper" types (Integer, Long, Double, Byte, etc), often called boxed types. These are heap allocated objects which are passed by reference, and exist in parallel to the primitive types mentioned above.

In more recent versions of Java, primitive types are automatically boxed into object types when necessary. This relieves most of the burden of managing them but it can also cause subtle bugs (see also auto-boxing).

In contrast to C#, in Java, the built-in JDK Collections framework always manages collections of object pointers. In order to make them parametric in a backward-compatible fashion, Java performs a technique called type-erasure, where (during runtime) everything is treated as an object inside the container (parameterised type checks are performed at compile time).

This means that you cannot make a Java List<int>, you can only make List<Integer>. And, the list above actually stores an array of pointers to boxed Integer objects, which is double the size and substantially less performant than the C# version. For most use cases, this difference in size and performance is irrelevant.

In use cases where size and performance are relevant, there are two options available:

  1. When you know the size of your list in advance, use an array of native types, for example int[]. Arrays of native types are packed in memory so they consume A LOT less memory and are more performant.
  2. When you do not know the size of your list in advance, use some 3rd party list implementation that wraps the native array, making it possible to add elements to it after creation (some examples: Trove, Colt, Fastutil, Guava).

OTHER TIPS

This is actually not true of C# either, not all types derive from objects, just like 99.9% of them. There exist a couple of very strange types that cannot be turned into objects. The only officially supported one is pointers. There are 3 more unsupported one like TypedReference, RuntimeArgumentHandle and a third whose name escapes me. Those 3 types are used with interop with variable length methods in C++/C. I wouldn't worry about them too much.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top