@head @title The dynamic type and mixed typing

Alore programs may freely mix static and dynamic typing. You can do this in a few different ways:

Note that local variables are different. If the enclosing function is dynamically-typed, the type checker ignores them (defaulting to dynamic typing). If the enclosing function has a type signature, the type checker infers the types of local variables. @h2 The type dynamic

If a variable has type dynamic, it is dynamically typed and no operations on it are checked statically. Consider this example: @example var d as dynamic d = 'x' d = 1 d + 'y' --E: Runtime error @end

Since d has type dynamic, the type checker does not give any errors. However, the program generates an exception at runtime. @h2 Implicit dynamic types

Global variables, member variables and functions are given dynamic types if they have no other types.

The following global variable definitions are equivalent: @example var Foo var Foo as dynamic @end

The following method signatures are equivalent: @example def foo(a, b) ... end def foo(a as dynamic, b as dynamic) as dynamic ... end @end

However, as the second method has explicit types (even though they are all dynamic), the body will use type inference. In the first method foo, the type checker will just ignore the body. @h2 Type compatibility

Every type is compatible with the type dynamic, and vice versa. This allows you to smoothly integrate dynamically-typed and statically-typed code. Consider this example, which defines a dynamically-typed and a statically-typed function that call each other: @example def D(n) if n == 0 return 0 else return S(n - 1) + 1 end end def S(n as Int) as Int if n == 0 return 1 else return D(n - 1) * 2 end end @end

Note that S calls D with argument of type Int, while D expects dynamic; and vice versa. Neither needs any casts.

Assignment works in a similar way: @example var n = 0 as Int var d = 1 as dynamic d = n -- Ok n = d -- Ok @end @h2 Running programs with mixed typing

When you run a program, the interpreter first erases all type declarations. The interpreter thus ignores static types at runtime. This happens behind the scenes and is not directly visible.

Here are a few examples of how erasing types works (we use ==> to mean erasure): @example var a = 5 as Int ==> var a = 5 def next(i as Int) as Int return i + 1 end ==> def next(i) return i + 1 end var a = [] as <Int> ==> var a = [] @end

Note that erasure does not remove normal casts, but it removes dynamic casts. For example: @example var o = 1 as Object var n = (o as Int) -- Normal cast var d = (o as dynamic) -- Dynamic cast ==> var o = 1 var n = (o as Int) var d = (o) @end @h2 Runtime type errors and mixed typing

Due to type erasue, some apparent type errors do not result in type errors at runtime: @example var i as Int var d = 'x' i = d -- Ok @end

The example assign a Str object to an Int variable. There is no static error since d has type dynamic; there is no runtime error since the type Int of i is erased before running the program.

A future Alore version will likely allow catching these kinds of type error. It will probably have two execution modes: a loose mode is equivalent to type erasure, while a strict mode detects cases like the example above. @h2 Generic types and dynamic typing

Mixed typing also supports objects of generic types. You can create a generic instance such as Array in dynamically-typed code and pass it to statically-typed code, and vice versa: @example var d = [1, 3] as dynamic Sum(d) -- Ok def Sum(a as Array<Int>) as Int var sum = 0 for n in a sum += a end return sum end @end

You can also use dynamic as a type argument. In this case, dynamic is compatible with any type. For example, Array<dynamic> is compatible with Array<Str>. @h2 Dynamic casts

You can use dynamic as the target type of a cast. This operation does nothing at the runtime, and it only selectively removes type checking from an expression. This allows you to bypass some restrictions of the type system: @example var ao = [1] as Array<Object> var ai as Array<Int> ai = ao --E: Type check error ai = (ao as dynamic) -- Ok (but be careful!) @end @h2 Inheritance and mixed typing

A dynamically-typed class may inherit a statically-typed class, and override some of its methods: @example class S def next(n as Int) as Int return n + 1 end end class D is S def next(n) -- Ok return n + 2 end end @end

This is useful especially in dynamically-typed programs that inherit statically-typed library classes. A dynamically-typed program or module does not need to care whether modules that it uses use static typing or not.

A statically-typed class can also inherit a dynamically-typed class, but this is less commonly useful. You can even change individual argument types to dynamic when overriding, while keeping others statically typed: @example class S2 def f(i as Int, s as Str) ... end end class D2 is S2 def f(i as Int, s as dynamic) -- Ok ... end end @end