There’s a lot of confusion floating around on the Internet over the subject of type system characteristics. People seem to have a lot of difficulty agreeing on the meaning of terms like “statically typed” and “type-safe”. The most difficult for people to agree on, however, seems to be “strongly typed” (and, by association, its antonym: “weakly typed”). Many people, it seems, have come to the conclusion that the only way to deal with the situation is to discard any use of certain type system characteristic terms entirely, because they are effectively “meaningless” due to the ubiquity of disagreement and misunderstanding.
Of course, that’s an absurd approach to take. If you just discard type system terminology that allows you to differentiate between type systems, you cease to be able to differentiate. Such differentiation is often important to being able to understand what you’re doing when programming, or choosing a programming language for a given task. Understanding the type system characteristics of a given language is as important as understanding the primary programming paradigm of the language, notational rules, semantics, naming conventions, and any other characteristics of a given language.
Worse yet, I have heard it said that various type system characteristics are actually just “implementation details”, rather than actual characteristics of the language. The truth is that actual type system characteristics are reflected in the language’s syntax — if you change the implementation from, say, runtime typing to compile-time typing, you change the language from dynamically typed to statically typed. This, in turn, alters the language: in such a circumstance as changing the implementation from enforcing dynamic to static typing, you impose a requirement for either type notation or type inference semantics, for instance. You may also fundamentally alter type safety, if nothing else about the language changes, and may eliminate certain forms of polymorphism that are not compatible with the language’s syntax and semantics in a statically typed context.
Given time and thought, over a period of some years, I’ve arrived at a fairly firm and internally consistent understanding of what various terms for type system characteristics mean. The definitions of these common terms, as I understand them, are orthogonal to each other and individually meaningul. They agree with the statements of recognized experts who have cause to know what they’re talking about, they eschew the largely meaningless bleatings of people just trying to make a given language sound better than another, and they agree with clearly understood interpretations of the actual English language meanings of the words used. Here they are:
type-safety: A type-safe language is one whose core type system does not allow for type errors at runtime. Such a language is almost impossible while still being a useful general-purpose language, but many languages come close enough to warrant the term “type-safe” for common usage. By contrast, a type-unsafe language in its purest meaning is one that does nothing to prevent type errors at all.
statically typed: A statically typed language is one that determines types at compile time. By contrast, a dynamically typed language is one that determines types at runtime, generally based on context.
strongly typed: A strongly typed language is one that does not allow the programmer to simply dodge the type system and where any instantiated or applied datum has a given type that cannot be changed, explicitly or implicitly. By contrast, a weakly typed language provides casts, bit manipulation, and other in-place conversions or evasions to subvert types.
duck typing: This is a more recent term than these others related to typing, and arose with the Ruby community. It essentially refers to a language that allows for a type to be unset until the datum to be typed has a typable value, at which point the type is “obvious” and set in stone. The most common implementation of this uses dynamic typing, but there are static type systems that could be called “duck typed”, such as OCaml and Objective C — though in OCaml’s case, it is achieved through type inference, and in Objective C it is limited to object types and is determined by behavior rather than type inference.
That makes OCaml type-safe, statically typed, strongly typed, and arguably duck typed (depending on how you use it). It also makes Ruby duck typed, type-safe, dynamically typed, and strongly typed; it makes Perl type-safe, dynamically typed, and strongly typed; it makes C statically typed, weakly typed, and kind of half-assed type-safe if you’re careful; it makes C++ less type-safe, weakly typed (though slightly more strongly typed than C), and statically typed, as well as allowing you to fake duck typing via templates and the like; it makes Objective C statically typed, exactly as half-assed type-safe as C, half-assed strongly typed (more so than C or C++), and duck typed insofar as its object system is concerned; it makes PHP weakly typed, dynamically typed, and type-unsafe; it makes Java fairly type-safe, weakly typed, and statically typed; and it makes Pascal statically typed, weakly typed, and mostly type-safe.
At least, that’s what comes to mind off the top of my head.