Static vs Dynamic, Strong vs Weak Typing
Two independent axes people constantly conflate
"Is Python strongly typed or weakly typed?" is the kind of question that starts fights, mostly because people are answering two different questions at once. There are two separate axes here, and they are independent. Get them straight and the confusion goes away.
Static vs dynamic: when the type is associated#
This axis is about when a value gets associated with a type.
In a dynamically typed language — Python, JavaScript — you bind a value to a name without declaring its type up front. The type is associated at runtime, based on what the value actually is.
x = 5 # x holds an int now
x = "hello" # the same name now holds a string, no complaints
In a statically typed language — C#, Java — you state the type before compile time, and the compiler checks it.
int x = 5;
x = "hello"; // compile error: cannot assign string to int
So static versus dynamic is purely about timing: compile-time declaration versus runtime association. It says nothing about how strict the language is once a type is known.
Strong vs weak: whether implicit conversions are allowed#
This axis is about whether the language will silently convert between types for you.
A strongly typed language refuses to quietly mix types. If you want to combine a string and a number, you convert explicitly.
int n = 5;
string s = "count: " + n.ToString(); // explicit conversion required
// "count: " + n on its own would not silently work the way you might expect
A weakly typed language performs implicit conversions automatically, guessing at your intent.
let n = 5;
let s = "count: " + n; // "count: 5" — number coerced to string automatically
console.log(1 + "2"); // "12", not 3 — JavaScript coerces happily
The axes are independent#
The whole point is that these two axes do not move together. Three quick placements make that clear:
- Python is dynamic and strongly typed. You do not declare types, but Python will not silently add a string to a number —
"a" + 1raises an error. - C# is static and strongly typed. You declare types, and conversions must be explicit.
- JavaScript is dynamic and weakly typed. No declarations, and it coerces between types eagerly.
That covers three of the four corners with mainstream languages, which is usually enough to end the argument.
The broader ways languages differ#
Typing is only one of several dimensions along which languages vary. When you are comparing two languages, it helps to think across all of these:
- Typing — static or dynamic, strong or weak, as above.
- Paradigms — object-oriented, functional, procedural, or some blend.
- Syntax — the surface grammar and how expressive or terse it is.
- Level — high-level (abstracted away from the machine) versus low-level (close to the hardware).
- Compiled vs interpreted — translated to machine code ahead of time, or executed by a runtime.
- Memory management — manual (you allocate and free) versus garbage-collected (the runtime reclaims memory for you).
Keep the two typing axes separate in your head, and the rest of these comparisons get a lot cleaner too.