I'm not really into type-safety as a concept
Maybe you should be.
for code to scale well, be reusable, be robust etc... it needs to be type safe.
I don't think it needs to be type safe, though it surely does help. Lots of people write code in C++, a language which has relatively weak type safety (because pointers can be converted to and from arbitrary integers). Nevertheless, C++ is also a language which has been designed to encourage code reuse via robust code encapsulated in classes.
Also, don't confuse static type checking with type safety. Some would argue that dynamically-checked languages are every bit as "type safe"; they just do their type system verifications at runtime instead of compile time.
Langueges like C# take type-safety seriously
Indeed.
generics in C# are considerably more typesafe than C++ templates.
I don't see any evidence for this assertion. Type checking on generics is different than type checking on templates, but both are type checked. The fundamental difference is that a generic assumes that any type that meets the constraints could be the type argument and therefore requires the program to pass static type checking for any possible type argument. Templates on the other hand only require the type arguments that you actually use to pass static type checking.
Even ArrayList which is considered not as typesafe as List<T>
being that it is a List<object>
is much more typesafe than for example a List<dynamic>
, which I think should be possible but is certainly obscure.
Well, dynamic is an interesting case. Like I said before, dynamic basically means "move the type checking of this thing to runtime".
I wonder why, again using C# as an example there is still null. I can see how in some respects it is faster than ensuring everything is constructed by default but isn't it a huge type-safety issue
You are right to raise this concern; nulls do throw a difficult problem at the type checker. One would like a statically-typed language to be "memory safe" -- to ensure that no invalid bit pattern ever makes its way into a variable annotated with a particular type. C# (outside of the unsafe subset) achieves this goal except that the all-zero null reference bit pattern is always legal in a variable annotated with a reference type, even though that bit pattern refers to no valid object.
You can certainly come up with languages that do not have null references and are statically type checked; Haskell is a good example. Why not do the same in C#?
Historical reasons. Null references are very useful, despite their dangers, and C# comes out of a long tradition of programming languages which allow null references.
I personally would have preferred it if we'd baked nullability into the framework from day one, so that you could have nullable or non-nullable value types, and nullable or non-nullable reference types. Remember that the next time you design a type system from scratch.
also requires extra time-consuming runtime checking for the computer to throw null exceptions and the such
That's actually not that bad. The way these things are usually implemented is the virtual memory page that contains the null pointer is marked as not readable, writable or executable. An attempt to do so then results in an exception raised by the hardware. And even in the cases where you do have to do a null check, comparing a register to zero is pretty quick.
There are worse problems. For example, arrays aren't "type safe" either in the sense that you can't statically type check whether a program is guaranteed to access only valid indices of an array. The CLR does a lot of work to make sure that every array access is valid.
Unsafe array covariance is also problematic; this is a bona-fide problem with the type system. We have to do type checks every time you write an element of a more-derived type to an array of its base type. That's my candidate for "worst feature" of the CLR.