# Getting started

is a multi-threaded functional engine with dynamic symbol bindings that supports the object oriented paradigm. The system features a state of the art runtime engine that runs on both 32 and 64 bits platforms. The system specification offers a rich syntax that makes the functional programming a pleasant activity. When the interpreter is used interactively, text is entered on the command line and executed when a complete and valid syntactic object has been constructed. Alternatively, the interpreter can execute a source file or operates with in stream.

is a comprehensive set of application clients, modules and services. The original distribution contains the core interpreter with additional clients like the compiler, the librarian and the debugger. The distribution contains also a rich set of modules that are dedicated to a particular domain. The basic modules are the standard i/o module, the system module and the networking module. Above modules are services. A service is another extension of the engine that provides extra functionalities with help of several modules. This hierarchy is strictly enforced in the system design and provides a clear functional separation between application domain. When looking for a particular feature, it is always a good idea to think in term of module functionality.

operates with a set of keywords and predicates. The engine has a native Unicode database. The set of standard objects provides support for integers, real numbers, strings, characters and boolean. Various containers like list, vector, hash table, bitset, and graphs are also available in the core distribution. The syntax incorporates the concept of lambda expression with explicit closure. Symbol scope limitation within a lambda expression is a feature called gamma expression. Form like notation with an easy block declaration is also another extension with respect to other system. The object model provides a single inheritance mechanism with dynamic symbol resolution. Special features include instance parenting, class binding instance inference and deference. Native class derivation and method override is also part of the object model with fixed class objects and forms. The engine incorporates an original regular expression engine with group matching, exact or partial match and substitution. An advanced exception engine is also provided with native run-time compatibility.

implements a true multi-threaded engine with an automatic object protection mechanism against concurrent access. A read and write locking system which operates with the thread engine is also built in the core system. The object memory management is automatic inside the core interpreter. Finally, the engine is written in C++ and provides runtime compatibility with it. Such compatibility includes the ability to instantiate C++ classes, use virtual methods and raise or catch exceptions. A comprehensive programming interface has been designed to ease the integration of foreign libraries.

## First contact

The fundamental syntactic object is a form. A form is parsed and immediately executed by the interpreter. A form is generally constructed with a function name and a set of arguments. The process of executing a form is called the evaluation. The next example illustrates one of the simplest form which is supported by the engine. This form simply displays the message hello world.

### Hello world

At the interpreter prompt, a form is constructed with the special object `println`. The unique argument is a string which is placed between double quotes.

(axi) println "Hello World" Hello World

The interpreter can be invoked to enter one or several forms interactively. The form can also be placed in a text file and the interpreted called to execute it. The als is the referred extension for a text file, but it can be anything. A simple session which executes the above file -- assuming the original file is called hello.als -- is shown below.

zsh> axi hello.als Hello World

In interactive mode, the interpreter waits for a form. When a form is successfully constructed, it is then immediately executed by the engine. Upon completion, the interpreter prompt is displayed and the interpreter is ready to accept a new form. A session is terminated by typing `ctrl-d`. Another way to use the engine is to call the compiler client called axc, and then invoke the interpreter with the compiled file. The interpreter assumes the .axc extension for compiled file and will automatically figure out which file to execute when a file name is given without an extension.

zsh> axc hello.als zsh> axi hello.axc Hello World zsh> axi hello Hello World

The order of search is determined by a special system called the file resolver. Its behavior is described in a special chapter of this manual.

### Interpreter command

The interpreter can be invoked with several options, a file to execute and some program arguments. The `h` option prints the various interpreter options.

zsh> axi -h usage: axi [options] [file] [arguments] [h] print this help message [v] print system version [m] enable the start module [i path] add a resolver path [e mode] force the encoding mode [f assert] enable assertion checks [f nopath] do not set initial path [f noseed] do not seed random engine [f seed] seed random engine

The `v` option prints the interpreter version and operating system. The `f` option turns on or off some additional options like the assertion checking. The use of program arguments is illustrated later in this chapter. The `i` option adds a path to the interpreter resolver. Several `i` options can be specified. The order of search is determined by the option order. As mentioned earlier, the use of the resolver combined with the librarian is described in a specific chapter. If the initial file name to execute contains a directory path, such path is added automatically to the interpreter resolver path unless the `nopath` option is specified.

### Interactive line editing

Line editing capabilities is provided when the interpreter is used interactively. Error messages are displayed in red if the terminal supports colors. Various accelerators are bound to the terminal as indicated in the table below.

### Interactive line editing key bindings

Binding | Description
--- | ---
backspace | Erase the previous character
delete | Erase at the cursor position
insert | Toggle insert with in-place
ctrl-a | Move to the beginning of the line
ctrl-e | Move to the end of the line
ctrl-u | Clear the input line
ctrl-k | Clear from the cursor position
ctrl-l | Refresh the line editing

The arrow are also bound to their usual functions. Note that when using the history, a multi-line command editing access is provided by the interpreter.

### Arrow key bindings

Binding | Description
--- | ---
left | Move the cursor to the left
right | Move the cursor to the right
up | Move up in the history list
down | Move down in the history list

### Command line arguments

The interpreter command line arguments are stored in a vector called `argv` which is part of the `interp` object. A complete discussion about object and class is covered in the class object chapter. At this time, it is just necessary to note that a method is invoked by a name separated from the object symbol name with a semicolon. The example below illustrates the use of the vector argument.

# argv.als # print the argument length and the first one println "argument length: " (interp:argv:length) println "first argument : " (interp:argv:get 0)

zsh> axi argv.als hello world 2 hello

### Loading a source file

The interpreter object provides also the `load` method to load a file. The argument must be a valid file path or an exception is raised. The `load` method returns `nil`. When the file is loaded, the interpreter input, output and error streams are used. The load operation reads one form after another and executes them sequentially.

# load the source file demo.als (axi) interp:load "demo.als"

# load the compiled file demo.axc (axi) interp:load "demo.axc"

# load whatever is found (axi) interp:load "demo"

The `load` method operates with the help of the interpreter resolver. By default the source file extension is als. If the file has been compiled, the axc extension can be used instead. This force the interpreter to load the compiled version. If you are not sure, or do not care about which file is loaded, the extension can be omitted. Without extension, the compiled file is searched first. If it is not found the source file is searched and loaded.

### The compiler

The client `axc` is the cross compiler. It generates a binary file that can be run across several platforms. The `h` option prints the compiler options.

usage: axc [options] [files] [h] print this help message [v] print version information [i] path add a path to the resolver [e mode] force the encoding mode

One or several files can be specified on the command line. The source file is searched with the help of the resolver. The resolver `i` option can be used to add a path to the resolver.

## Writing structure

The structure of file is a succession of valid syntactic objects separated by blank lines or comments. During the compilation or the execution process, each syntactic object is processed one after another in a single pass. Reserved keywords are an intergral part of the writing systems. The association of symbols and literal consistutes a form. A form is the basic execution block in the writing system. When the form uses reserved keyword, it is customary to refer to it as a special form.

### Character set and comments

The writing system operates with the standard Unicode character set. Comments starts with the character `#`. All characters until the end of line are consumed. Comments can be placed anywhere in the source file. Comments entered during an interactive session are discarded.

### Native objects

The writing system operates mostly with objects. An object is created upon request or automatically by the engine when a native representation is required. To perform this task, several native objects, namely `Boolean` for boolean objects, `Integer` , `Relatif` for integer numbers, `Real` for floating-point number, `Byte`, `Character` and `String` for character or string manipulation are built inside the engine. Most of the time, a native object is built implicitly from its lexical representation, but an explicit representation can also be used.

const boolean true const integer 1999 const relatif 1234567890R const real 2000.0 const string "afnix" const char 'a'

trans symbol "hello world" trans symbol 2000

The `const` and `trans` reserve keywords are used to declare a new symbol. A symbol is simply a binding between a name and an object. Almost any standard characters can be used to declare a symbol. The `const` reserved keyword creates a constant symbol and returns the last evaluated object. As a consequence, nested `const` constructs are possible like `trans b (const a 1)`. The `trans` reserved keyword declare a new transient symbol. When a symbol is marked transient, the object bound to the symbol can be changed while this is not possible with a constant symbol. Eventually, a symbol can be destroyed with the special form `unref`. It is worth to note that it is the symbol which is destroyed and not the object associated with it.

### Stop and resume parsing

The parsing process is stopped in the presence of the `«` character. The parsing operation is resumed with the `»` character. Such mechanism is useful when dealing with multi line statements.

### Forms

An implicit form is a single line command. When a command is becoming complex, the use of the standard form notation is more readable. The standard form uses the `(` and `)` characters to start and close a form. A form causes an evaluation. When a form is evaluated, each symbol in the form are evaluated to their corresponding internal object. Then the interpreter treats the first object of the form as the object to execute and the rest is the argument list for the calling object. The use of form inside a form is the standard way to perform recursive evaluation with complex expressions.

const three (+ 1 2)

This example defines a symbol which is initialized with the integer 3, that is the result of the computation `(+ 1 2)`. The example shows also that a Polish notation is used for arithmetic. If fact, `+` is a built-in operator which causes the arguments to be summed (if possible). Evaluation can be nested as well as definition and assignation. When a form is evaluated, the result of the evaluation is made available to the calling form. If the result is obtained at the top level, the result is discarded.

const b (trans a (+ 1 2)) assert a 3 assert b 3

This program illustrates the mechanic of the evaluation process. The evaluation is done recursively. The `(+ 1 2)` form is evaluated as 3 and the result transmitted to the form `(trans a 3)`. This form not only creates the symbol `a` and binds to it the integer 3, but returns also 3 which is the result of the previous evaluation. Finally, the form `(const b 3)` is evaluated, that is, the symbol `b` is created and the result discarded. Internally, things are a little more complex, but the idea remains the same. This program illustrates also the usage of the `assert` keyword.

### Lambda expression

A lambda expression is another name for a function. The term comes historically from Lisp to express the fact that a lambda expression is analog to the concept of expression found in the lambda calculus. There are various ways to create a lambda expression. A lambda expression is created with the `trans` reserved keyword. A lambda expression takes 0 or more arguments and returns an object. A lambda expression is also an object by itself When a lambda expression is called, the arguments are evaluated from left to right. The function is then called and the object result is transmitted to the calling form. The use of `trans` vs `const` is explain later. To illustrate the use of a lambda expression, the computation of an integer factorial is described in the next example.

# declare the factorial function trans fact (n) ( if (== n 1) 1 (* n (fact (- n 1))))

# compute factorial 5 println "factorial 5 = " (fact 5)

This example calls for several comments. First the `trans` keyword defines a new function object with one argument called `n`. The body of the function is defined with the `if` special form and can be easily understood. The function is called in the next form when the `println` special form is executed. Note that here, the call to `fact` produces an integer object, which is converted automatically by the `println` keyword.

### Block form

The notation used in the `fact` program is the standard form notation originating from Lisp and the Scheme dialect. There is also another notation called the block form notation with the use of the `{` and `}` characters. A block form is a syntactic notation where each form in the block form is executed sequentially. The form can be either an implicit or a regular form. The `fact` procedure can be rewritten with the block notation as illustrated below.

# declare the factorial procedure trans fact (n) { if (== n 1) 1 (* n (fact (- n 1))) }

# compute factorial 5 println "factorial 5 = " (fact 5)

Another way to create a lambda expression is via the `lambda` special form. Recall that a lambda expression is an object. So when such object is created, it can be bounded to a symbol. The factorial example could be rewritten with an explicit lambda call.

# declare the factorial procedure const fact (lambda (n) ( if (== n 1) 1 (* n (fact (- n 1)))))

# compute factorial 5 println "factorial 5 = " (fact 5)

Note that here, the symbol `fact` is a constant symbol. The use of `const` is reserved for the creation of gamma expression.

### Gamma expression

A lambda expression can somehow becomes very slow during the execution, since the symbol evaluation is done within a set of nested call to resolve the symbols. In other words, each recursive call to a function creates a new symbol set which is linked with its parent. When the recursion is becoming deep, so is the path to traverse from the lower set to the top one. There is also another mechanism called gamma expression which binds only the function symbol set to the top level one. The rest remains the same. Using a gamma expression can speedup significantly the execution.

# declare the factorial procedure const fact (n) ( if (== n 1) 1 (* n (fact (- n 1))))

# compute factorial 5 println "factorial 5 = " (fact 5)

We will come back later to the concept of gamma expression. The use of the reserved keyword `const` to declare a gamma expression makes now sense. Since most function definitions are constant with one level, it was a design choice to implement this syntactic sugar. Note that `gamma` is a reserved keyword and can be used to create a gamma expression object. On the other hand, note that the gamma expression mechanism does not work for instance method. We will illustrate this point later in this book.

### Lambda generation

A lambda expression can be used to generate another lambda expression. In other word, a function can generate a function, an that capability is an essential ingredient of the functional programming paradigm. The interesting part with lambda expression is the concept of closed variables. In the next example, looking at the lambda expression inside `gen`, notice that the argument to the gamma is `x` while `n` is marked in a form before the body of the gamma. This notation indicates that the gamma should retain the value of the argument `n` when the closure is created. In the literature, you might discover a similar mechanism referenced as a closure. A closure is simply a variable which is closed under a certain context. When a variable is reference in a context without any definition, such variable is called a free variable. We will see later more programs with closures. Note that it is the object created by the lambda or the gamma call which is called a closure.

# a gamma which creates a lambda const gen (n) ( lambda (x) (n) (+ x n))

# create a function which add 2 to its argument const add-2 (gen 2)

# call add-2 with an argument and check println "result = " (add-2 3)

In short, a lambda expression is a function with or without closed variables, which works with nested symbol sets also called namesets. A gamma expression is a function with or without closed variable which is bounded to the top level nameset. The reserved keyword `trans` binds a lambda expression. The reserved keyword `const` binds a gamma expression. A gamma expression cannot be used as an instance method.

### Multiple arguments binding

A lambda or gamma expression can be defined to work with extra arguments using the special `args` binding. During a lambda or gamma expression execution, the special symbol `args` is defined with the extra arguments passed at the call. For example, a gamma expression with 0 formal argument and 2 actual arguments has `args` defined as a cons cell.

const proc-nilp (args) { trans result 0 for (i) (args) (result:+= i) eval result } assert 3 (proc-nilp 1 2) assert 7 (proc-nilp 1 2 4)

The symbol `args` can also be defined with formal arguments. In that case, `args` is defined as a cons cell with the remaining actual arguments.

# check with arguments const proc-args (a b args) { trans result (+ a b) for (i) (args) (result:+= i) eval result } assert 3 (proc-args 1 2) assert 7 (proc-args 1 2 4)

It is an error to specify formal arguments after `args`. Multiple `args` formal definition are not allowed. The symbol `args` can also be defined as a constant argument.

# check with arguments const proc-args (a b (const args)) { trans result (+ a b) for (i) (args) (result:+= i) eval result } assert 7 (proc-args 1 2 4)

## Nameset and bindings

A nameset is a container of bindings between a name and symbolic variable. We use the term symbolic variable to denote any binding between a name and an object. There are various ways to express such bindings. The most common one is called a symbol. Another type of binding is an argument. Despite the fact they are different, they share a set of common properties, like being settable. Another point to note is the nature of the nameset. As a matter of fact, there is various type of namesets. The top level nameset is called a global set and is designed to handle a large number of symbols. In a lambda or gamma expression, the nameset is called a local set and is designed to be fast with a small number of symbols. The moral of this little story is to think always in terms of namesets, no matter how it is implemented. All namesets support the concept of parent binding. When a nameset is created (typically during the execution of a lambda expression), this nameset is linked with its parent one. This means that a symbol look-up is done by traversing all nameset from the bottom to the top and stopping when one is found. In term of notation, the current nameset is referenced with the special symbol `.`. The parent nameset is referenced with the special symbol `..`. The top level nameset is referenced with the symbol `...`.

### Symbol

A symbol is an object which defines a binding between a name and an object. When a symbol is evaluated, the evaluation process consists in returning the associated object. There are various ways to create or set a symbol, and the different reserved keywords account for the various nature of binding which has to be done depending on the current nameset state. One of the symbol property is to be `const` or not. When a symbol is marked as a constant, it cannot be modified. Note here that it is the symbol which is constant, not the object. A symbol can be created with the reserved keywords `const` or `trans`.

### Creating a nameset

A nameset is an object which can be constructed directly by using the object construction notation. Once the object is created, it can be bounded to a symbol. Here is a nameset called `example` in the top level nameset.

# create a new nameset called example const example (nameset .)

# bind a symbol in this nameset const example:hello "hello" println example:hello

### Qualified name

In the previous example, a symbol is referenced in a given nameset by using a qualified name such like `example:hello`. A qualified name defines a path to access a symbol. The use of a qualified name is a powerful notation to reference an object in reference to another object. For example, the qualified name `.:hello` refers to the symbol `hello` in the current nameset. The qualified name `...:hello` refers to the symbol `hello` in the top level nameset. There are other use for qualified names, like method call with an instance.

### Symbol binding

The `trans` reserved keyword has been shown in all previous example. The reserved keyword `trans` creates or set a symbol in the current nameset. For example, the form `trans a 1` is evaluated as follow. First, a symbol named `a` is searched in the current nameset. At this stage, two situations can occur. If the symbol is found, it is set with the corresponding value. If the symbol is not found, it is created in the current nameset and set. The use of qualified name is also permitted -- and encouraged -- with `trans`. The exact nature of the symbol binding with a qualified name depends on the partial evaluation of the qualified name. For example, `trans example:hello 1` will set or create a symbol binding in reference to the `example` object. If `example` refers to a nameset, the symbol is bound in this nameset. If `example` is a class, `hello` is bounded as a static symbol for that class. In theory, there is no restriction to use `trans` on any object. If the object does not have a symbol binding capability, an exception is raised. For example, if `n` is an integer object, the form `trans n:i 1` will fail.

With 3 or 4 arguments, `trans` defines automatically a lambda expression. This notation is a syntactic sugar. The lambda expression is constructed from the argument list and bounded to the specified symbol. The rule used to set or define the symbol are the same as described above.

# create automatically a lambda expression trans min (x y) (if (< x y) x y)

### Constant binding

The `const` reserved keyword is similar to `trans`, except that it creates a constant symbol. Once the symbol is created, it cannot be changed. This constant property is hold by the symbol itself. When trying to set a constant symbol, an exception is raised. The reserved keyword `const` works also with qualified names. The rules described previously are the same. When a partial evaluation is done, the partial object is called to perform a constant binding. If such capability does not exist, an exception is raised.

With 3 or 4 arguments, `const` defines automatically a gamma expression. Like `trans` the rule are the same except that the symbol is marked constant.

# create automatically a gamma expression const max (x y) (if (> x y) x y)

### Symbol unreferencing

The `unref` reserved keyword removes a symbol reference in a given context. When the context is a nameset, the object associated with the symbol is detached from the symbol, eventually destroyed with the symbol removed from the nameset.

# create a symbol number const x 1 # unreference it unref x

### Arguments

An expression argument is similar to a symbol, except that it is used only with function argument. The concept of binding between a name and an object is still the same, but with an argument, the object is not stored as part of the argument, but rather at another location which is the execution stack. An argument can also be constant. On the other hand, a single argument can have multiple bindings. Such situation is found during the same function call in two different threads. An argument list is part of the lambda or gamma expression declaration. If the argument is defined as a constant argument a sub form notation is used to defined this matter. For example, the `max` gamma expression is given below.

# create a gamma expression with const argument const max (gamma ((const x) (const y)) (if (> x y) x y))

A special symbols named `args` is defined during a lambda or gamma expression evaluation with the remaining arguments passed at the time the call is made. The symbol can be either `nil` or bound to a list of objects.

const proc-args (a b) { trans result (+ a b) for (i) (args) (result:+= i) eval result } assert 3 (proc-args 1 2) assert 7 (proc-args 1 2 4)

## Special forms

Special forms provides are reserved keywords which are most of the time imperative statement, as part of the writing system. Special forms are an integral part of the writing system and interact directly with the interpreter. In most cases, a special forms returns the last evaluated object. Most of the special forms are control flow statements.

### If special form

The `if` reserved keyword takes two or three arguments. The first argument is the boolean condition to check. If the condition evaluates to `true` the second argument is evaluated. The form return the result of such evaluation. If the condition evaluates to `false`, the third argument is evaluated or nil is returned if it does not exist. An interesting example which combines the `if` reserved keyword and a deep recursion is the computation of the Fibonacci sequence.

const fibo (gamma (n) ( if (< n 2) n (+ (fibo (- n 1)) (fibo (- n 2))))

### While special form

The `while` reserved keyword takes 2 or 3 arguments. With 2 arguments, the loop is constructed with a condition and a form. With 3 arguments, the first argument is an initial condition that is executed only once. When an argument acts as a loop condition, the condition evaluate to a boolean. The loop body is executed as long as the boolean condition is true. An interesting example related to integer arithmetic with a `while` loop is the computation of the greatest common divisor or gcd.

const gcd (u v) { while (!= v 0) { trans r (u:mod v) u:= v v:= r } eval u }

Note in this previous example the use of the symbol `=`. The qualified name `u:=` is in fact a method call. Here, the integer `u` is assigned with a value. In this case, the symbol is not changed. It is the object which is muted.

In the presence of 3 arguments, the first argument is an initialization condition that is executed only once. In this mode, it is important to note that the loop introduce its own nameset. The loop condition can be used to initialize a local condition variable.

while (trans valid (is:valid-p)) (valid) { # do something # adjust condition valid:= (and (is:valid-p) (something-else)) }

### Do special form

The `do` reserved keyword is similar to the `while` reserved keyword, except that the loop condition is evaluated after the body execution. The syntax call is opposite to the `while`. The loop can accept either 2 or 3 arguments. With 2 arguments, the first argument is the loop body and the second argument is the exit loop condition. With 3 arguments, the first argument is the initial condition that is executed only once.

# count the number of digits in a string const number-of-digits (s) { const len (s:length) trans index 0 trans count 0 do { trans c (s:get index) if (c:digit-p) (count:++) } (< (index:++) len) eval count }

### Loop special form

The `loop` reserved keyword is another form of loop. It take four arguments. The first is the initialize form. The second is the exit condition. The third is the step form and the fourth is the form to execute at each loop step. Unlike the `while` and `do` loop, the `loop` special form creates its own nameset, since the initialize condition generally creates new symbol for the loop only.

# a simple loop from 0 to 10 loop (trans i 0) (< i 10) (i:++) (println i)

A loop can also be designed with a `Counter` object. In this case, a counter is created with an initial and final count values. The counter `step-p` method can then be used to run the loop

# a counter from 0 to 10 trans cntr (Counter 10) # a simple loop from 1 to 10 loop (cntr:step-p) (println cntr)

In this example, the counter prints from 1 to 10 since the counter is designed to operate from 0 to 9, and the `println` function is called after the `step-p` predicate.

### Switch special form

The `switch` reserved keyword is a condition selector. The first argument is the switch selector. The second argument is a list of various value which can be matched by the switch value. A special symbol called `else` can be used to match any value.

# return the primary color in a rgb const get-primary-color (color value) ( switch color ( ("red" (return (value:substr 0 2))) ("green" (return (value:substr 2 4))) ("blue" (return (value:substr 4 6))) ))

### Return special form

The `return` reserved keyword indicates an exceptional condition in the flow of execution within a lambda or gamma expression. When a return is executed, the associated argument is returned and the execution terminates. If `return` is used at the top level, the result is simply discarded.

# initialize a vector with a value const vector-init (length value) { # treat nil vector first if (<= length 0) return (Vector) trans result (Vector) do (result:add value) (> (length:--) 0) }

### Eval and protect

The `eval` reserved keyword forces the evaluation of the object argument. The reserved keyword `eval` is typically used in a function body to return a particular symbol value. It can also be used to force the evaluation of a protected object. In many cases, `eval` is more efficient than `return`. The `protect` reserved keyword constructs an object without evaluating it. Typically when used with a form, `protect` return the form itself. It can also be used to prevent a symbol evaluation. When used with a symbol, the symbol object itself is returned.

const add (protect (+ 1 2)) (eval add)

Note that in the preceding example that the evaluation will return a lambda expression which is evaluated immediately and which return the integer 3.

### Assert special form

The `assert` reserved keyword check for equality between the two arguments and abort the execution in case of failure. By default, the assertion checking is turn off, and can be activated with the command option `f assert`. Needless to say that `assert` is used for debugging purpose.

assert true (> 2 0) assert 0 (- 2 2) assert "true" (String true)

### Block special form

The `block` reserved keyword executes a form in a new local set. The local set is destroyed at the completion of the execution. The `block` reserved keyword returns the value of the last evaluated form. Since a new local set is created, any new symbol created in this nameset is destroyed at the completion of the execution. In other word, the `block` reserved keyword allows the creation of a local scope.

trans a 1 block { assert a 1 trans a (+ 1 1) assert a 2 assert ..:a 1 } assert 1 a

## Built-in objects

Several built-in objects and built-in operators for arithmetic and logical operations are also integrated in the writing system. The `Integer` and `Real` classes are primarily used to manipulate numbers. The `Boolean` class is used to for boolean operations. Other built-in objects include `Character` and `String`. The exact usage of these objects is described in the next chapter.

### Arithmetic operations

Support for the arithmetic operations is provided with the standard operator notation. Normally, these operators will tolerate various object type mixing and the returned value will generally be bound to an object that provides the minimum loss of information. Most of the operations are done with the `+`, `-`, `*` and `/` operators.

(+ 1 2) (- 1) (* 3 5.0) (/ 4.0 2)

### Logical operations

The `Boolean` class is used to represent the boolean value `true` and `false`. These last two symbols are built-in in the interpreter as constant symbols. There are also special forms like `not`, `and` and `or`. Their usage is self understandable.

not true and true (== 1 0) or (< -1 0) (> 1 0)

### Predicates

A predicate is a function which returns a boolean object. There is always a built-in predicate associated with a built-in object. By convention, a predicate terminates with the sequence -p. The `nil-p` predicate is a special predicate which returns true if the object is nil. The `object-p` predicate is the negation of the `nil-p` predicate.

### Built-In predicates

Predicate | Description
--- | ---
nil-p | check nil object
eval-p | check evaluation
real-p | check real object
regex-p | check regex object
object-p | check for non nil object
string-p | check string object
number-p | check number object
method-p | check method object
boolean-p | check boolean object
integer-p | check integer object
character-p | check character object

For example, one can write a function which returns `true` if the argument is a number, that is, an integer or a real number.

# return true if the argument is a number const number-p (n) ( or (integer-p n) (real-p n))

Special predicates for functional and symbolic programming are also built-in in the engine.

### Special predicates

Predicate | Description
--- | ---
class-p | check class object
thread-p | check thread object
promise-p | check promise object
lexical-p | check lexical object
literal-p | check literal object
closure-p | check closure object
nameset-p | check nameset object
instance-p | check instance object
qualified-p | check qualified object

Finally, for each object, a predicate is also associated. For example, `cons-p` is the predicate for the `Cons` object and `vector-p` is the predicate for the `Vector` object. Another issue related to evaluation, is to decide whether or not an object can be evaluated. The predicate `eval-p` which is a special form is designed to answer this question. Furthermore, the `eval-p` predicate is useful to decide whether or not a symbol is defined or if a qualified name can be evaluated.

assert true (eval-p .) assert false (eval-p an-unknown-symbol)

## Class and instance

Classes and instances are the fundamental object that provide support for the object oriented programming paradigm. A class is a nameset which can be bounded automatically when an instance of that class is created. The class model is sloppy. Compared to other systems, there is no need to declare the data members for a particular class. Data members are created during the instance construction. An instance can also be created without any reference to a class. Methods can be bound to the class or the instance or both. An instance can also be muted during the execution process.

### Class and members

A class is declared with the reserved keyword `class`. The resulting object acts like a nameset and it is possible to bind symbol to it.

# create a class object const Circle (class) const Circle:PI 3.1415926535 # access by qualified name println Circle:PI

In the previous example, the symbol `Circle` is created as a class object. With the help of a qualified name, the symbol `PI` is created inside the class nameset. In this case, the symbol `PI` is invariant with respect to the instance object. Such mechanism is also called static binding in other programming systems. A form can also be bound to the class nameset. In both cases, the symbol or the form is accessed with the help of a qualified name.

### Instances

An instance of a class is created like any built-in object. If a method called `preset` is defined for that class, the method is used to initialize the instance.

# create a class const Circle (class) trans Circle:preset (r) { const this:radius (r:clone) } # create a radius 1 circle const c (Circle 1)

This example calls for several comments. First the `preset` lambda expression is bound to the class. Since `preset` is a reserved name for the class object, the form is automatically executed at the instance construction. Second, note that the instance data member `radius` is created by the lambda expression and another reserved keyword called `this` is used to reference the instance object as it is customary with other programming systems.

### Instance method

When a lambda expression is bound to the class or the instance, that lambda can be invoked as an instance method. When an instance method is invoked, the instance nameset is set as the parent nameset for that lambda. This is the main reason why a gamma expression cannot be used as an instance method. Therefore, the use of the reserved keyword `this` is not recommended in a gamma expression, although it is perfectly acceptable to create a symbol with such name.

# create a perimeter method trans Circle:perimeter nil ( * (* 2.0 Circle:PI) this:radius) # call the method with our circle trans p (c:perimeter)

It must be clear that the `perimeter` symbol defines a method at the class level. It is perfectly acceptable to define a methods at the instance level. Such method is called a specialized method.

## Miscellaneous features

### Iteration

An iteration facility is provided for some objects known as iterable objects. The `Cons`, `List` and `Vector` are typical iterable objects. There are two ways to iterate with these objects. The first method uses the `for` reserved keyword. The second method uses an explicit iterator which can be constructed by the object.

# compute the scalar product of two vectors const scalar-product (u v) { trans result 0 for (x y) (u v) (result:+= (* x y)) eval result }

The `for` reserved keyword iterate on both object `u` and `v`. For each iteration, the symbol `x` and `y` are set with their respective object value. In the example above, the result is obtained by summing all intermediate products.

# test the scalar product function const v1 (Vector 1 2 3) const v2 (Vector 2 4 6) (scalar-product v1 v2)

The iteration can be done explicitly by creating an iterator for each vectors and advancing steps by steps.

# scalar product with explicit iterators const scalar-product (u v) { trans result 0 trans u-it (u:get-iterator) trans v-it (v:get-iterator) while (u:valid-p) { trans x (u:get-object) trans y (v:get-object) result:+= (* x y) u:next v:next } eval result }

In the example above, two iterators are constructed for both vectors `u` and `v`. The iteration is done in a `while` loop by invoking the `valid-p` predicate. The `get-object` method returns the object value at the current iterator position.

### Exception

An exception is an unexpected change in the execution flow. The exception model is based on a mechanism which throws the exception to be caught by a handler. The mechanism is also designed to be compatible with the native "C++" implementation.

An exception is thrown with the special form `throw`. When an exception is thrown, the normal flow of execution is interrupted and an object used to carry the exception information is created. Such exception object is propagated backward in the call stack until an exception handler catch it.

The special form `try` executes a form and catch an exception if one has been thrown. With one argument, the form is executed and the result is the result of the form execution unless an exception is caught. If an exception is caught, the result is the exception object. If the exception is a native one, the result is nil.

try (+ 1 2) try (throw) try (throw "hello") try (throw "hello" "world") try (throw "hello" "world" "folks")

The exception mechanism is also designed to install an exception handler and eventually retrieve some information from the exception object. The reserved symbol `what` can be used to retrieve some exception information.

# protected factorial const fact (n) { if (not (integer-p n)) (throw "number-error" "invalid argument") if (== n 0) 1 (* n (fact (- n 1))) } # exception handler const handler nil { errorln what:eid ',' what:reason } (try (fact 5) handler) (try (fact "hello") handler)

The special symbol `what` stores the necessary information about the place that generated the exception. Most of the time, the qualified name `what:reason` or `what:about` is used.The only difference is that `what:about` contains the file name and line number associated with the reason that generated the exception.

### Regular Expressions

A regular expression or regex is an object which is used to match certain text patterns. Regular expressions are built implicitly by the parser with the use of the `[` and `]` characters. Special class of characters are defined with the help of the `$` character. For example, `$d` is the class of character digits as defined by the Unicode consortium. Different regular expression can be grouped by region to be matched as indicated in the example below.

if (== (const re [($d$d):($d$d)]) "12:31") { trans hr (re:get 0) trans mn (re:get 1) }

In the previous example, a regular expression object is bound to the symbol `re`. The `regex` contains two groups. The call to the operator `==` returns `true` if the regex matches the argument string. The `get` method can be used to retrieve the group by index.

### Delayed evaluation

The special form `delay` creates a special object called a promise which records the form to be later evaluated. The special form `force` causes a promise to be evaluated. Subsequent call with `force` will produce the same result.

trans y 3 const l ((lambda (x) (+ x y)) 1) assert 4 (force l) trans y 0 assert 4 (force l)

## Threads

The interpreter provides a powerful mechanism which allows the concurrent execution of forms and the synchronization of shared objects. There is a single type of thread called normal thread. The interpreter wait until all normal threads are completed. Normal threads are created with the reserved keyword `launch`. When threads are used, the interpreter manages automatically the shared objects and protect them against concurrent access.

# shared variable access const var 0

const decr nil (while true (var:= (- var 1))) const incr nil (while true (var:= (+ var 1))) const prtv nil (while true (println "value = " var))

# start 3 threads launch (prtv) launch (decr) launch (incr)

### Form synchronization

Although, the engine provides an automatic synchronization mechanism for reading or writing an object, it is sometimes necessary to control the execution flow. There are basically two techniques to do so. First, protect a form from being executed by several threads. Second, wait for one or several threads to complete their task before going to the next execution step. The reserved keyword `sync` can be used to synchronize a form. When a form, is synchronized, the engine guarantees that only one thread will execute this form.

const print-message (code mesg) ( sync { errorln "error : " code errorln "message: " mesg } )

The previous example create a gamma expression which make sure that both the error code and error message are printed in one group, when several threads call it.

### Thread completion

The other piece of synchronization is the thread completion indicator. The thread descriptor contains a method called `wait` which suspend the calling thread until the thread attached to the descriptor has been completed. If the thread is already completed, the method returns immediately.

# simple flag const flag false

# simple shared tester const ftest (bval) (flag:= bval)

# run the thread and wait const thr (launch (ftest true)) thr:wait assert true flag

This example is taken from the test suites. It checks that a boolean variable is set in a thread. Note the use of the `wait` method to make sure the thread has completed before checking for the flag value. It is also worth to note that `wait` is one of the method which guarantees that a thread result is valid.

Another use of the `wait` method can be made with a vector of thread descriptors when one wants to wait until all of them have completed.

# shared vector of threads descriptors const thr-group (Vector)

# wait until all threads in the group are finished const wait-all nil (for (thr) (thr-group) (thr:wait))

### Condition variable

A condition variable is another mechanism to synchronize several threads. A condition variable is modeled with the `Condvar` object. At construction, the condition variable is initialized to `false`. A thread calling the `wait` method will block until the condition becomes `true`. The `mark` method can be used by a thread to change the state of a condition variable and eventually awake some threads which are blocked on it. The use of condition variable is particularly recommended when one need to make sure a particular thread has been doing a particular task.

## The interpreter object

The interpreter can also be seen as an object. As such, it provides several special symbols and forms. For example, the symbol `argv` is the argument vector. The symbol `library` is an interpreter method that loads a library. A complete description of the interpreter object is made in a special chapter of this book.