Is EK9 statically or dynamically typed?
← Getting Started · Ref: Q27
EK9 is statically and strongly typed. All types are resolved at compile time. There are no runtime type errors from incorrect assignments, no 'undefined is not a function', no AttributeError because a method does not exist. If it compiles, the types are correct.
But EK9 does not feel like a statically typed language. Type inference means you rarely write type annotations for local variables:
count <- 42 name <- "Steve" ratio <- 3.14 items <- List() of String
The compiler infers Integer, String, Float, and List of String. You get the safety of static typing with the brevity of dynamic typing.
WHEN YOU MUST DECLARE TYPES
Type annotations are required in specific places where inference is not possible or where clarity matters:
Parameters: -> operand as Integer (always required) Return values: <- result as String (always required) Explicit base types: shape as Shape: Circle() (when you want the variable typed as the base) Properties: name <- String() (class/record fields)
WHEN YOU SHOULD NOT DECLARE TYPES
For local variables where the type is obvious from the right-hand side, let inference do the work:
count <- 42 (not count as Integer: 42) name <- "hello" (not name as String: "hello") today <- Date() (not today as Date: Date())
Declaring the type when inference can determine it is redundant and reduces readability.
WHY NOT DYNAMIC TYPING?
Dynamic languages (Python, JavaScript, Ruby) defer type checking to runtime. This means:
Python: name = 42; name.upper() compiles fine but crashes at runtime with AttributeError JavaScript: '5' - 3 gives 2 but '5' + 3 gives '53'. Type coercion rules are inconsistent and produce silent bugs. Ruby: method_missing can intercept any call, making it impossible to know at edit time whether a method exists
These bugs are found in production, not during development. Every dynamic language eventually grows optional type systems (Python type hints, TypeScript, Sorbet for Ruby) because runtime type errors are too expensive in production.
EK9 starts with static types so you never need to retrofit safety later. The compiler catches type mismatches, missing methods, incorrect operator usage, and incompatible assignments before your code ever runs.
STRONG TYPING
EK9 is also strongly typed. There are no implicit conversions except the single-level promote operator (see Q25). You cannot accidentally treat a String as an Integer or a Boolean as a number. The type system enforces boundaries and the compiler reports violations as errors, not warnings.
COMPILE-TIME GUARANTEES
Because EK9 is statically typed, the compiler can guarantee:
Every method call resolves to an actual method Every operator is defined on the type it is applied to Every assignment is type-compatible (or has a valid promotion) Every function parameter matches the expected type Every return value matches the declared return type Generic types are fully resolved and checked
See also Q22 (How do I declare a variable?) for type inference syntax and Q25 (What is the promote operator?) for the single automatic type widening mechanism.
See Q23 for basic types. See Q29 for unset variables. See Q257 for constrained types that restrict values at the type level.
Example
defines module qa.static.typing defines function addValues() as pure -> first as Integer second as Integer <- result as Integer: first + second defines program StaticTypingDemo() stdout <- Stdout() // Type inference - compiler knows the types count <- 42 name <- "Steve" ratio <- 3.14 items <- List() of String items += "one" items += "two" // Explicit type when you want a base type floatValue as Float: count // All types checked at compile time result <- addValues(count, 10) stdout.println(`${name}: ${result}`) stdout.println(`Ratio: ${ratio}`) stdout.println(`Items: ${items}`) stdout.println(`Float: ${floatValue}`)
Common mistakes
E50060 — EK9 resolves methods on the type they are defined on. Calling a standalone function as if it were a method on Integer would trigger method-not-found. See ek9 -h E50060 for details.
Incorrect:
result <- count.addValues(10)
Correct:
result <- addValues(count, 10)
Other ways to ask this
- Does EK9 check types at compile time or runtime?
- How does type inference work in EK9?
- Do I have to declare types for every variable in EK9?
- Is EK9 strongly typed?
Coming from another language?
Python: dynamically typed, type hints optional (PEP 484), runtime AttributeError. JavaScript: dynamically typed, TypeScript added for safety, implicit coercion ('5'+3='53'). Ruby: dynamically typed, Sorbet added. Java: statically typed but verbose (var added Java 10). Kotlin: statically typed with inference. Rust: statically typed with inference. Go: statically typed with := inference. EK9: statically typed with <- inference, feels dynamic, catches everything at compile time.
Keywords: beginner, compile, start, dynamic, typed, type, runtime, anonymous, inference, check, intro, first, typing, capture, migrate, safety, infer, strong, static, closure