Actually Java works in the same way; the confusion stems from imprecise use of jargon. Java tends to use the word "type" for things which would more precisely be called "tags". Tags are the run-time information which distinguish different values of the same type, and can't be erased in general.
Java adds a bunch of rules about handling tags, for example object values have a "class" tag; class tags must be statically specified (AKA "type signatures"); class tags can be pattern-matched automatically (AKA dynamic dispatch, method overloading and inheritance), allowing functions to be defined in separate chunks (AKA methods); functions can only be applied to arguments which will match a pattern (AKA "type checking"), etc.
These rules are checked at compile time as well as the types. Unfortunately all these different concepts tend to be grouped under the umbrella term "type checking", which makes fine-grained discussion and comparisons to other languages more difficult.
Actually Java works in the same way; the confusion stems from imprecise use of jargon. Java tends to use the word "type" for things which would more precisely be called "tags". Tags are the run-time information which distinguish different values of the same type, and can't be erased in general.
Java adds a bunch of rules about handling tags, for example object values have a "class" tag; class tags must be statically specified (AKA "type signatures"); class tags can be pattern-matched automatically (AKA dynamic dispatch, method overloading and inheritance), allowing functions to be defined in separate chunks (AKA methods); functions can only be applied to arguments which will match a pattern (AKA "type checking"), etc.
These rules are checked at compile time as well as the types. Unfortunately all these different concepts tend to be grouped under the umbrella term "type checking", which makes fine-grained discussion and comparisons to other languages more difficult.