Make Inko a fully statically typed language
Summary
Inko is currently a gradually typed language. I hoped it would provide a balance between the safety of a statically typed language, and the rapid prototyping that a dynamic language allows for. But as it turns out, dynamic typing is not useful for Inko, and inhibits or complicates various optimisations.
Gradual typing should be removed, and Inko should become a statically typed language.
Motivation
Gradual typing is useful when applied to a language that is dynamic by default.
But when the language is static by default, it does not prove many benefits. In
the places where Inko currently uses dynamic typing, we can replace it with the
use of an Any
trait implemented by all objects.
Dynamic typing also inhibits or complicates certain optimisations. For example, in #174 (closed) it is discussed to change how keyword arguments are implemented. Specifically, it is discussed to make them a compile-time only construct. This however means keyword arguments are not supported for dynamic types. This is just one example where dynamic types may not support all features, with probably more to come.
Another example where dynamic types prove problematic is method lookups. At the moment Inko uses hash maps, but in the future we may want to use a different approach; one that may not be supported for dynamic types. Some languages approach this by supporting/using different approaches where needed, but I would like to not complicate Inko with this.
Gradual typing was also meant to act as a bridge between a fully dynamically typed program, and a statically typed one. For example, you could write a dynamically typed program and incrementally make it statically typed. In practise, this turns out not to be particularly useful, and quite annoying at times. For example:
import std::stdio::stdout
def add_and_print(a, b) {
let c = a + b
stdout.print(c)
}
stdout.print
requires a ToString
, but c
is a Dynamic
. This requires a
cast, and probably some sort of runtime type check. Having to do this often,
which will likely be needed, is frustrating and ultimately brings no value.
Gradual typing should go, and Inko should become a fully statically typed language.
Implementation
First we introduce a Any
trait, probably available to all traits by default.
This trait is implemented by all objects when they are defined. This can be
implemented by desugaring an object
expression into an object
and impl
expression.
Once introduced, we replace all existing uses of Dynamic
with the Any
trait.
Method and closure signatures need to be handled differently. Method arguments
will require either an explicit type, a default value, or both. This means code
such as def foo(a) {}
is no longer valid. Leaving method return types out will
result in the return type being inferred as Nil
. Closure arguments are to be
inferred to Any
instead of Dynamic
if no better type can be found.
In !81 (merged) we introduce pattern
matching. These match
blocks return a Dynamic
if arms return different
types. This should be changed to return an Any
instead.
Once implemented, an issue should be created to make sure we also update the website according to the new changes.
Drawbacks
It requires admitting I was wrong about gradual typing, and quite a bit of work; but it will be worth it.
Related work
Kotlin uses an Any
type:
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/.