Hi, Mr. Static Typer Tiger!
(be it Java, Rust, C++, C, Go, Haskell or even ugly little duckling TypeScript)
You are the kind of guy who does not play around in Adult Kindergarten:
You are not a toddler. You fight like a Man:
You are a Knight in Statically Typed Armor.
You, with the other honorable Knights, stand guard on top of the Type System to protect the Realm:
You, with your allies - the Knights of the Type Watch - keep a watchful eye over the kingdom.
The goal of this article is:
To build up in us some empathy towards people who use dynamically typed languages.
I want us to feel what dynamically typed people might feel, when they get force-fed our statically typed agenda.
Get the low hanging fruit out of the way
You probably know that in normal type systems, you can pull off crazy nonsense.
We'll be quick and only look at three.
Duck typing - Gary and his Ostrich
The most obvious cheap shot is of course duck typing and all the bonuses and maluses which come with it.
If it looks like a duck, quacks like a duck... it could be still living in pain:
We don't want to go into subtype vs. assignment, this is enough for us.
Covariance and Contravariance - Smoking Hot
A much more prevalent topic, which is not TypeScript specific, is that they allow a really macho thing: Smoking.
Let's see how smoking will pan out for our statically typed entourage...
We can play with Petrol in TypeScript easily even at runtime.
In TypeScript, if we have an array of SprayingPlayers we can add a last one which lights up a cigarette:
And this works in other languages too!
For example, Java:
We don't want to go into covariance vs. contravariance, this is enough for us.
The limits of static analysis - Forgetfulness
You could pickup everyone on Planet Earth... according to Groundhog day, because you'd have infinite amount of tries, and each time you fail, you'd learn about that person more, which you could use in your next encounters.
Unfortunately common type systems, do not play by the rules of Groundhog day.
Common static type systems cannot express evolving properties and invariants.
When you wake up, you will FORGET everything about what happened earlier.
Even if you discount type erasure and other mechanisms, type systems in general don't retain all of the information.
This is why we have:
- Static properties (deducible even by reading the code)
- Dynamic properties (deducible only by executing the code and possibly making side-effects)
For example, array bound checks must occur always:
But there are other languages than Java.
The Department of War, formerly known as the Department of Defense:
... developed a different language ...
In this language - amongst many other things - you can constrain the type of arrays to use a specific type of indices:
(indices are not necessarily numbers, but I used numbers because it is easier to digest that way)
Of course you can index into the array:
But if you index out of the array, you can tell it from the constraints:
The bounds check can be done by simply reading the code, aka static analysis.
Another simple example: Increment a number.
We can define the Increment procedure:
But we can also define a kind of mathematical statement or 'contract' about Increment:
Then we can use the computer to prove that Increment adheres to the 'contract'.
In our case, static analysis reveals an overflow in this simple code:
"Static" Type System, peon-cast
Rust, Java, C++, TS etc. devs often say they're fighting the type system.
I want to show you what "fight" means.
I'll use Java, but the same thing applies to Rust, C and even things like React.
Sorry, this will be a bit SOLID, but we're gonna cut to the juicy part really quickly, just bear with me.
There will be two Design Patterns before we get to the kickbox.
In Proxy pattern there's a Proxy between the real thing and the caller:
In Command pattern each action like click or hover is its own Command:
There's a Java library called Selenide which does a roundhouse kick.
It is a web browser automation library. You can click or setValue on a DOM element:
That $(...) gives back a JVM created ghost, which is hooked onto Proxy. The Proxy redirects(routes) all incoming calls to their respective Commands.
For example .setValue() to SetValue Command:
The SetValue does not know that its first - and only - argument is a String.
It just accesses into the args array and peon-casts the value:
Same thing applies to Rust, C and even things like React.
Example, peon-cast in Angular:
Or a low-hanging fruit peon-cast in C++:
Lads, let's learn a Song!
We are going to re-learn how types and 1 + 1 works, because apparently:
None of us listened in elementary school!
We'll sing along to a song, together lads!
You get bonus points if you keep up the pace with the lyrics!
Let's sing our Pirate Chantey!
No, we don't say "booty" ’less we talkin’ 'bout gold
We don’t look at chests 'less it's treasure holds!
With a hat and a feather and a cutlass on our hip
We don't ever say "she" when we’re talking 'bout a ship!
We don't say "b***h" and we don't say "w***e"
'Cause that language leads to things like body dysmorphiaaaaaaa
There was a lady with a golden eye
And the doctor said she would die
So she emptied her purse to lift the curse
And prayed to stay alive
She awoke the very next day
And in her grave she lay
But the scariest part of the story from the start...
Is I bet you assumed the doctor was a man
Women are doctors too
And for a fraction of the doubloons!
We say "Yo, ho!" but we don't say "ho"
'Cause "ho" is disrespectful, yo
There was a Next.js with hydration da' here and a json that -
'Cause it's "Yo, ho!" but we don't say "ho"
'Cause "ho" is disrespectful, yo
Arrr!












































Top comments (0)