The point of having static typing is the ability to prove statically that your program is correct with regard of types (note: not completely correct in all senses). If you have a static type system throughout, you can detect type errors most of the time.
If you only have partial type information, you can only check the small pieces of a call graph where type info happens to be complete. But you have spent time and effort to specify type information for incomplete parts, where it can't help you but could give a false sense of security.
To express type information, you need a part of language which cannot be excessively simple. Soon you'll find out that info like int
is not enough; you'll want something like List<Pair<Int, String>>
, then parametric types, etc. It can be confusing enough even in the rather simple case of Java.
Then, you'll need to handle this information during translation phase and execution phase, because it's silly to only check for static errors; the user is going to expect that the type constraints always hold if specified at all. Dynamic languages are not too fast as they are, and such checks will slow the performance down even more. A static language can spend serious effort checking types because it only does that once; a dynamic language can't.
Now imagine adding and maintaining all of this just so that people sometimes optionally used these features, only detecting a small fraction of type errors. I don't think it's worth the effort.
The very point of dynamic languages is to have a very small and very malleable framework, within which you can easily do things that are much more involved when done in a static language: various forms of monkey-patching that are used for metaprogramming, mocking and testing, dynamic replacement of code, etc. Smalltalk and Lisp, both very dynamic, took it to such an extreme as to ship environment images instead of building from source. But when you want to ensure that particular data paths are type-safe, add assertions and write more unit tests.
Update from 2020: Some dynamic languages now support partial typing of sorts. Python allows type hints, to be used by external tools like mypy
. TypeScript allows mixing with type-oblivious JavaScript. Still, the points above mostly hold.
Two features come to my mind:
Portability. In languages like C, where datatypes like int
are platform specific, an alias like DWORD
makes it easier to ensure you are really using a 32bit signed integer everywhere, when this is the requirement for your program, even when you port the program to a plattform where int
is e.g. 16bit unsigned and therefore DWORD
has to be an alias for signed long
.
Abstraction. In your program, you might use a lot of integer and floating point numbers for different purposes. By creating aliases like SPEED
, HEIGHT
, TEMPERATURE
, it's relatively easy to change one of those e.g. from float
to double
and leave the others as they are.
Best Answer
There are a few differences between Go and C that makes the former at least more type safe:
Unless you muck about with the unsafe package, you're not going to crash a Go program (in the sense that it won't do something that causes the OS to kill it). You may cause it to panic, but this is not the same thing as a crash (and it is recoverable).
Go does not have pointer arithmetic (source) -- although it does have null reference of sort called
nil
.Go's
void*
equivalent,interface{}
, is cast in a more safe manner using type assertions, which will not just crash and permit safer type testing, or type switches.Basically Go and languages with similar mixes of declared types and runtime types (C# and Java) are type safe because they supplement an unsound type system with a runtime type system that turns type errors that would have caused crashes into runtime exceptions.
C has an unsound type system and no runtime system that would prevent unsafe behavior.
Some languages, like ATS, also like runtime protections but are type-safe because their type systems make illegal operations unsayable.
Basically: type safe means the language won't let you do anything illegal.
Sometimes the runtime stops you (like in dynamic languages like Python).
Sometimes the type system stops you.
For Go it is a combination of both.