• No results found

It is advantageous when building and modifying systems at run-time (when live program- ming!) that errors be caught as early as possible. This is particularly important for a live systems programming language where the luxury of oine testing is either greatly limited or simply unavailable.

For live programming systems the ability to stop the world for debugging purposes is usually impossible, and always undesirable. The ability to catch errors statically is ad-

vantageous as it removes a class of run-time errors that would otherwise require run-time management. Prior work[77] demonstrated how heuristics can be used to automatically manage certain Scheme run-time errors. A video demonstrating this style of dynamic heuristic intervention in practice is provided in Appendix D. However these heuristic interventions would ultimately be better avoided in the rst place, and many such areas can be caught statically, before they become a run-time concern. In order to support greater static checking, XTLang includes a state type system.

XTLang's type system supports a standard array of primitive and aggregate types in- cluding 8bit, 32bit, 64bit and 128bit integers; 32bit and 64bit oating point types; tuples (transparent to C structs) and xed length arrays. Additionally Extempore supports a number of non-standard C primitive and aggregate types including a boolean type, sum types, a primitive SIMD vector type, and rst-class lexical closures. Finally XTLang supports indirect referencing via pointers to both primitive and aggregate types as well as supporting recursive named types (in the form of product and sum types).

Explicit type annotations and the constraints imposed by a static type system are often perceived as introducing unacceptable cognitive dissonance into the programming activity [35][56]. In the context of live programming these criticisms seem particularly damaging as the cognitive demands on the live programmer are already high. In an attempt to minimise the imposition of the type system, while maximising its benets, XTLang supports bounded polymorphism (ad-hoc polymorphism with rank 1 parametric overloading) and partial type inference.

Pierce and Turner[67] suggest three primary goals for a partial type inference algorithm in the service of a HOT5 (higher order, typed) programming language/programming

5A HOT programming style is a style in which (1) the use of higher order functions and anonymous

abstractions is encouraged; (2) polymorphic denitions are used freely and at a fairly ne grain (for individual function denitions rather than whole modules) and (3) pure data structures are used instead of mutable state whenever possible[67, p.2]. XTLang is a very HOT language with respect

style:

1. To make ne-grained polymorphism tolerable, type arguments in applications of polymorphic functions must usually be inferred. However, it is acceptable to re- quire annotations on the bound variables of top-level function denitions (since these provide useful documentation) and local function denitions (since these are relatively rare).

2. To make higher order programming convenient, it is helpful, though not absolutely necessary, to infer the type parameters to anonymous function denitions.

3. To support a mostly functional style (where the manipulation of pure data struc- tures leads to many local variable bindings), local bindings should not normally require explicit annotations.

XTLang conforms to these three goals with type inference supported for top-level function denitions, anonymous function denitions, and local variable bindings. Over- all, XTLang's type system, and inference system, have been heavily inuenced by the functional languages ML and Haskell, in addition to C whose ABI XTLang conforms to. The type [i64,i64,i64]* of gcd in Listing 17 is statically inferred by the XTLang compiler. In Listing 17 the type [i64,i64,i64]* is inferred because the integer literal `0' in the expression (equals b 0) defaults to a 64bit integer. This 64bit literal `0' is enough type information for the XTLang compiler to fully resolve the gcd function.

In XTLang, a function's type identies the return type rst, followed by any argument types. An XTLang function that takes a single 32bit integer argument and returns a double value would be type [double,i32]*. Functions in XTLang are references, which are specied, as in C, by an appended * for each level of indirection.

In Listing 18 the XTLang compiler infers the type [i32,i32,i32]* due to the explicit annotation of the literal 0:i32.

(bind-func gcd (lambda (a b) (if (= b 0:i32) a (gcd b (rem a b))))) ($ (gcd 15:i32 12))

Listing 18: GCD annotated with a 32bit integer literal

After evaluating both Listing 17 and Listing 18 the Extempore run-time will in- clude two XTLang specialisations of gcd, one for [i64,i64,i64]* and a second for [i32,i32,i32]*. XTLang's gcd function has become an ad-hoc polymorphic function. Ad-hoc due to the fact that each polymorphic variant is derived from an independent code base, with independent (ad-hoc) behaviour.

Ad-hoc polymorphism in XTLang (function overloading) resolves using both the return type of the function, as well as any argument types. Failure to fully resolve the type of an adhoc-polymorphic function results in a static type error. An important consideration in Listing 18 is the top-level expression ($ (gcd 15:i32 12)) used to call gcd, which explicitly denes the integer literal 15 as 32bit. Without this explicit declaration the 64bit specialisation of gcd would be called instead of the 32bit specialisation, for in this context, and without explicit annotation, the integers 15 and 12 would both default to 64bit integers (i64). It is sucient in this case to explicitly type only one of gcd's two arguments.

Variable declarations in XTLang can be explicitly typed. Listing 19 provides explicit types for a and b, which alleviates the need to type the literal 0 as in example 18.

Recompiling (i.e. re-evaluating) gcd in example 19 replaces the existing [i32,i32,i32]* specialisation from 18. In this example the behaviour would be identical, but in Live Coding performances it is often desirable to have divergent behaviour from function overloading.

(bind-func gcd

(lambda (a:i32 b:i32) (if (= b 0)

a

(gcd b (rem a b)))))

($ (gcd 15:i32 12))

Listing 19: GCD explicit 32bit arguments