Digital said:
I'm a bit confused by the terms {strong vs. weak} typing and
{static vs. dynamic} typing. Are they orthogonal terms? ie.
are there 4 combinations of these types of typing?
Yes. Note that I seem to have a different understanding than some other
posters.
From my understanding, static typing means that a variable's type
is always known at compile-time
Yes.
and that the compiler checks for
improper operations on a type at compile-time.
No. There's yet another distinction: a language can be type safe or
type unsafe (or somewhere in between). In a type safe language, type
errors (performing an operation that the object does not support) are
impossible. They may be blocked at compile time, which is typical but
not required of statically typed languages, or they may be blocked at
runtime. Java uses a mixed approach, while C and C++ have no runtime
checking. As a result, Java is type safe while C and C++ are not.
Also, AFAICT, strong typing means that improper operations on a type
are not allowed to happen.
No, that is type safe. Strong typing means that every expression has a
well defined type.
Does strong typing occur at compile time
or runtime?
Yes. (It can be either.)
If a language is statically typed, thereby preventing
illegal type operations at compile time,
Thus you mean statically typed *and* typesafe.
would you even need
strong typing at runtime?
No (except possibly for debugging purposes), and this is a strong
advantage of statically typed languages. However, there are reasons to
want to avoid statically typed languages; see below.
I've read that C and C++ are statically typed but not strongly
typed.
This is wrong. C and C++ are strongly typed because every expression
has a well defined type (or has type void, which is technically an
incomplete type and so counts). They are statically typed because the
types are known at compile time, which is why sizeof can do what it does.
C++ has some (weak) dynamic typing features, in addition.
I've also read that Java is statically and strongly typed.
Is this correct?
Yes, for the same reason. It also has dynamic typing features.
Suppose I have a simple program:
int i;
double j;
int result;
i = 2;
j = 3.0;
result = i+j;
This will compile in C/C++ (albeit with a warning). This will not
even compile in Java. What does this show about each language's
type-ness?
This demonstrates two things.
In Java the binary + operator is very heavily overloaded. It can accept
the following pairs of types.
int, int
long, long
float, float
double, double
But that's just for arithmetic. When you add in the String type, things
get much uglier. In C, it's even worse; the rules are very complicated
and I won't try to give them all here. (C++ is a downright Gordian knot
in this regard.) Overloading of operators is not strictly related to
type checking or type safety, but languages that place a large emphasis
on static type safety prefer to not overload operators (e.g. Ada or ML).
It also shows that, in both languages, there is the possibility for
implicit type conversions. In C, C++, and Java, integral types can be
implicitly converted to either float or double, and that is what is
happening here: the value of i is promoted to double, and then the
double, double form of the + operator is invoked.
In Java, however, there is no implicit type conversion from double to
int, and that is why it fails to compile. C and C++ do allow implicit
type conversions (that is, without a typecast) from double to int, which
is why the code compiles.
Implicit type conversions weaken the strong-typing aspect of a language:
the more implicit type conversions, the weaker the typing. They do not
affect type safety. So in this regard, Java is more strongly typed than
C or C++.
To be very sure:
In a statically typed language, the types are known at compile time.
In a dynamically typed language, the types are discovered at runtime.
In a strongly typed language, every expression has a well defined type.
In a weakly typed language, the types of expressions are undefined, or
malleable, or determined by context, etc..
Languages can also be totally untyped. Assembly is an example.
In a type safe language, operations that a type does not support are
impossible.
In a type unsafe language, operations that a type does not support are
possible.
A few examples:
SML is strongly typed, statically typed, and type safe.
C is strongly typed, statically typed, and type unsafe.
Smalltalk is strongly typed, dynamically typed, and type safe.
____ is strongly typed, dynamically typed, and type unsafe. (I can't
think of an example, since dynamically typed languages are typically
type safe).
Perl is weakly typed, dynamically typed, and type safe.
Assembly is untyped and type unsafe.
And a few weirdos:
Objective-C is weakly typed (expressions can have a well defined compile
time type, but this type is permitted to be wrong!), has *optional*
static typing, and is typesafe.
Dylan has *optional* strong typing, *optional* static typing, and is
type safe.
As an interesting factoid, type checking is related to the Halting
Problem, and it's known that no static type checker can determine
exactly which programs will produce a type error: they will either
reject some correct ones or admit some illegal ones. Dynamic type
checking does not have that problem.
I'm sure it's much clearer now.
-Peter