In the context of programming languages, many people seem to consider at least two of the terms “weak typing”, “dynamic typing” and “duck typing” to be synonymous. However, each of these has a completely different meaning and they can independently apply or not apply to a given language.
Strongly typed languages include Haskell, Rust, Nim, Julia, Python, Ruby, …
Weakly typed languages include C, JavaScript, PHP, Tcl, …
If you object to C being called a weakly typed language, consider the following example:
#include <fenv.h>
#include <stdio.h>
int main() {
int a = 42;
int b = &a;
int c = FE_TOWARDZERO;
int d = stdout;
printf("%d\n", a * b + c / d);
return 0;
}
Here we have three variables representing completely different things — one is an integer, one is a pointer, one is a flag for the floating point environment and one is a file handle. However, C allows us to declare them all as int
and perform arithmetic on them.
Statically typed languages include C, Java, Haskell, Nim, Rust, …
Dynamically typed languages include Python, Common Lisp, Ruby, JavaScript, PHP, …
Note that a statically typed language doesn't necessarily require type declarations to be present on all variable declarations. Consider the following Nim program:
import std/strutils
stdout.write "What's your height in meters? "
let height = stdin.readLine.parseFloat
stdout.write "What's your weight in kilograms? "
let weight = stdin.readLine.parseFloat
let bmi = weight / (height * height)
let diagnosis = "Your BMI is " & $bmi
stdout.writeLine diagnosis
There are no type annotations in this program, yet all types are known and checked at compile time thanks to type inference.
The definition may sound a bit cryptic, so let's see a concrete example. Consider the following Haskell code:
middle :: a -> a -> a -> a
middle x y z
| x <= y && y <= z = y
| z <= y && y <= x = y
| y <= x && x <= z = x
| z <= x && x <= y = x
| otherwise = z
Trying to compile this produces the following error:
.code.tio.hs:3:5: error: • No instance for (Ord a) arising from a use of ‘<=’ Possible fix: add (Ord a) to the context of the type signature for: middle :: forall a. a -> a -> a -> a • In the first argument of ‘(&&)’, namely ‘x <= y’ In the expression: x <= y && y <= z In a stmt of a pattern guard for an equation for ‘middle’: x <= y && y <= z | 3 | | x <= y && y <= z = y | ^^^^^^
This is because we've declared that middle
works for any type, but in fact it only works for types that support comparison. We can fix this by declaring that a
has to be an ordered type:
middle :: Ord a => a -> a -> a -> a
Now let's implement the same function in C++:
template <typename T> T middle(T x, T y, T z) {
if ((x <= y && y <= z) || (z <= y && y <= x)) {
return y;
}
if ((y <= x && x <= z) || (z <= x && x <= y)) {
return x;
}
return z;
}
C++ doesn't complain. When we try to use the function on a non-ordered type, that's when we're going to get into trouble, but otherwise it's cool. This makes C++ a duck-typed language, even though it's statically typed.
To comment, use this mailing list.