afnix-guide






vol‐1 ‐ afnix programmer’s guide

AFNIX 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, textis 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 an input stream.  AFNIX 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 or service
functionality.  AFNIX 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.  AFNIX 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









                             ‐2‐


integration of foreign libraries.

     Firstcontact
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.

     Helloworld
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 alsis 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 .axcextension 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.

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









                             ‐3‐


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 voption prints the interpreter version and operating
system. The foption turns on or off some additional options
like the assertion checking. The use of program arguments is
illustrated later in this chapter. The ioption adds a path
to the interpreter resolver. Several ioptions can be
specified. The order of search is determined by the option
order. As mentioned earlier, the use of the resolver
combined with the librarianis 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 nopathoption is
specified.

     editingInteractiveline
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.

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.

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












                             ‐4‐


     argumentsCommandline
The interpreter command line arguments are stored in a
vector called argvwhich is part of the interpobject. 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


     sourceLoadinga
The interpreter object provides also the loadmethod to load
a file. The argument must be a valid file path or an
exception is raised. The loadmethod 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 loadmethod operates with the help of the interpreter
resolver. By default the source file extension is als. If
the file has been compiled, the axcextension 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.

     Thecompiler
The client axcis the cross compiler. It generates a binary
file that can be run across several platforms. The hoption
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.









                             ‐5‐


The source file is searched with the help of the resolver.
The resolver ioption can be used to add a path to the
resolver.

     Writingstructure
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 integral part of the writing systems. The
association of symbols and literal constitutes 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.

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

     Nativeobjects
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 Booleanfor boolean objects,
Integer, Relatiffor integer numbers, Realfor floating‐point
number, Byte, Characterand Stringfor 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 constand transreserve 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 constreserved keyword creates a
constant symboland returns the last evaluated object. As a
consequence, nested constconstructs are possible like trans
b (const a 1). The transreserved 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









                             ‐6‐


that it is the symbol which is destroyed and not the object
associated with it.

     resumeStopand
The parsing process is stopped in the presence of the
âcharacter (Unicode U+25C0). The parsing operation is
resumed with the â¶character (Unicode U+25B6). Such
mechanism is useful when dealing with multi line statements.
This mechanism is also a good example of Unicode based
control characters.

     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 aand
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 bis 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 assertkeyword.

     Lambdaexpression
A lambda expressionis 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









                             ‐7‐


found in the lambda calculus. There are various ways to
create a lambda expression. A lambda expression is created
with the transreserved 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 transvs constis 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
transkeyword defines a new function object with one argument
called n. The body of the function is defined with the
ifspecial form and can be easily understood. The function is
called in the next form when the printlnspecial form is
executed. Note that here, the call to factproduces an
integer object, which is converted automatically by the
printlnkeyword.

     Blockform
The notation used in the factprogram is the standard form
notation originating from Lisp and the Scheme dialect. There
is also another notation called the block formnotation 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 factprocedure 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
lambdaspecial 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









                             ‐8‐


println "factorial 5 = " (fact 5)

Note that here, the symbol factis a constant symbol. The use
of constis reserved for the creation of gamma expression.

     Gammaexpression
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
expressionwhich 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 constto 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 gammais 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.

     Lambdageneration
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 programmingparadigm. 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 xwhile nis
marked in a form before the body of the gamma. This notation
indicates that the gamma should retain the value of the
argument nwhen 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) (









                             ‐9‐


  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 transbinds a lambda
expression. The reserved keyword constbinds a gamma
expression. A gamma expression cannot be used as an instance
method.

     bindingMultiplearguments
A lambda or gamma expression can be defined to work with
extra arguments using the special argsbinding. During a
lambda or gamma expression execution, the special symbol
argsis defined with the extra arguments passed at the call.
For example, a gamma expression with 0 formal argument and 2
actual arguments has argsdefined 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 argscan also be defined with formal arguments. In
that case, argsis 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 argsformal definition are not allowed. The symbol
argscan 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
}









                            ‐10‐


assert 7 (proc‐args 1 2 4)


     bindingsNamesetand
A namesetis a container of bindings between a name and
symbolic variable. We use the term symbolic variableto
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 setand is designed to handle a large number
of symbols. In a lambda or gamma expression, the nameset is
called a local setand 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 namesetis referenced with the special symbol ’.’.
The parent namesetis referenced with the special symbol
’..’. The top level namesetis 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 constor
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 constor trans.

     namesetCreatinga
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 examplein 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










                            ‐11‐


     Qualifiedname
In the previous example, a symbol is referenced in a given
nameset by using a qualified namesuch 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 .:hellorefers to the symbol helloin the
current nameset. The qualified name ...:hellorefers to the
symbol helloin the top level nameset. There are other use
for qualified names, like method call with an instance.

     Symbolbinding
The transreserved keyword has been shown in all previous
example. The reserved keyword transcreates or set a symbol
in the current nameset. For example, the form trans a 1is
evaluated as follow. First, a symbol named ais 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 1will set or create a symbol
binding in reference to the exampleobject. If examplerefers
to a nameset, the symbol is bound in this nameset. If
exampleis a class, hellois bounded as a class symbol. In
theory, there is no restriction to use transon any object.
If the object does not have a symbol binding capability, an
exception is raised. For example, if nis an integer object,
the form trans n:i 1will fail. With 3 or 4 arguments,
transdefines 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)


     Constantbinding
The constreserved 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 constworks 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, constdefines automatically a gamma expression.
Like transthe rule are the same except that the symbol is
marked constant.









                            ‐12‐


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


     Symbolunreferencing
The unrefreserved 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 maxgamma 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 argsis 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 nilor 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)


     Specialforms
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









                            ‐13‐


cases, a special forms returns the last evaluated object.
Most of the special forms are control flow statements.

     formIfspecial
The ifreserved keyword takes two or three arguments. The
first argument is the boolean condition to check. If the
condition evaluates to truethe 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 ifreserved 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))))


     formWhilespecial
The whilereserved 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 whileloop 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 uis 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))
}










                            ‐14‐


     formDospecial
The doreserved keyword is similar to the whilereserved
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
}


     formLoopspecial
The loopreserved 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
whileand doloop, the loopspecial 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 Counterobject. In this
case, a counter is created with an initial and final count
values. The counter step‐pmethod 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
printlnfunction is called after the step‐ppredicate.

     formSwitchspecial
The switchreserved 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 elsecan be used to









                            ‐15‐


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)))
  ))


     formReturnspecial
The returnreserved 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
returnis 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)
}


     protectEvaland
The evalreserved keyword forces the evaluation of the object
argument. The reserved keyword evalis 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, evalis more efficient than return. The
protectreserved keyword constructs an object without
evaluating it. Typically when used with a form,
protectreturn 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.

     formAssertspecial
The assertreserved 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 assertis used for debugging purpose.










                            ‐16‐


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


     formBlockspecial
The blockreserved keyword executes a form in a new local
set. The local set is destroyed at the completion of the
execution. The blockreserved 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
blockreserved 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‐inobjects
Several built‐in objects and built‐in operators for
arithmetic and logical operations are also integrated in the
writing system. The Integerand Realclasses are primarily
used to manipulate numbers. The Booleanclass is used to for
boolean operations. Other built‐in objects include
Characterand String. The exact usage of these objects is
described in the next chapter.

     Arithmeticoperations
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)


     Logicaloperations
The Booleanclass is used to represent the boolean value
trueand false. These last two symbols are built‐in in the
interpreter as constant symbols. There are also special
forms like not, andand or. Their usage is self
understandable.










                            ‐17‐


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


     Predicates
A predicateis 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‐ppredicate is a special predicate
which returns true if the object is nil. The object‐
ppredicate is the negation of the nil‐ppredicate.

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 trueif
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.

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‐pis the predicate for the Consobject and
vector‐pis the predicate for the Vectorobject. Another issue
related to evaluation, is to decide whether or not an object









                            ‐18‐


can be evaluated. The predicate eval‐pwhich is a special
form is designed to answer this question. Furthermore, the
eval‐ppredicate 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)


     instanceClassand
Classes and instances are the fundamental objects that
provide support for the object oriented paradigm. A classis
a nameset which can be bounded automatically when an
instanceof 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.

     membersClassand
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 Circleis created as a
class object. With the help of a qualified name, the symbol
PIis created inside the class nameset. In this case, the
symbol PIis invariant with respect to the instance object. 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 presetis 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









                            ‐19‐


presetlambda expression is bound to the class. Since
presetis a reserved name for the class object, the form is
automatically executed at the instance construction. Second,
note that the instance data member radiusis created by the
lambda expression and another reserved keyword called thisis
used to reference the instance object as it is customary
with other programming systems.

     Instancemethod
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 thisis
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 perimetersymbol 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.

     Miscellaneousfeatures

     Iteration
An iteration facility is provided for some objects known as
iterable objects. The Cons, Listand Vectorare typical
iterable objects. There are two ways to iterate with these
objects. The first method uses the forreserved 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 forreserved keyword iterate on both object uand v. For
each iteration, the symbol xand yare 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)









                            ‐20‐


(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 uand v. The iteration is done in a whileloop by
invoking the valid‐ppredicate. The get‐objectmethod returns
the object value at the current iterator position.

     Exception
An exceptionis 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 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 tryexecutes 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 whatcan be
used to retrieve some exception information.

# protected factorial









                            ‐21‐


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 whatstores the necessary information
about the place that generated the exception. Most of the
time, the qualified name what:reasonor what:aboutis used.The
only difference is that what:aboutcontains the file name and
line number associated with the reason that generated the
exception.

     RegularExpressions
A regular expression or regexis 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, $dis 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 regexcontains two groups. The
call to the operator ==returns trueif the regex matches the
argument string. The getmethod can be used to retrieve the
group by index.

     Delayedevaluation
The special form delaycreates a special object called a
promisewhich records the form to be later evaluated. The
special form forcecauses a promise to be evaluated.
Subsequent call with forcewill 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)












                            ‐22‐


     Threads
The interpreter provides a powerful mechanism which allows
the concurrent execution of forms and the synchronization of
shared objects. The engine provides supports the creation
and the synchronization of threads with a native object
locking mechanism. During the execution, the interpreter
wait until all threads are completed. A threads is created
with the reserved keyword launch. In the presence of several
threads, 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)


     Formsynchronization
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 synccan 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.

     Threadcompletion
The other piece of synchronization is the thread completion
indicator. The thread descriptor contains a method called
waitwhich 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









                            ‐23‐


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
waitmethod to make sure the thread has completed before
checking for the flag value. It is also worth to note that
waitis one of the method which guarantees that a thread
result is valid. Another use of the waitmethod 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))


     Conditionvariable
A condition variableis another mechanism to synchronize
several threads. A condition variable is modeled with the
Condvarobject. At construction, the condition variable is
initialized to false. A thread calling the waitmethod will
block until the condition becomes true. The markmethod 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.

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

This chapters covers in detail the literals objects used to
manipulate numbers and strings. First the integer, relatif
and real numbers are described. There is a broad range of
methods for these three objects that support numerical
computation. As a second step, string and character objects
are described. Many examples show the various operations
which can be used as automatic conversion between one type
and another. Finally, the boolean object is described. These
objects belongs to the class of literal objects, which are
objects that have a string representation. A special literal
object known as regular expressionor regexis also described
at the end of this chapter.










                            ‐24‐


     Integernumber
The fundamental number representation is the Integer. The
integer is a 64 bits signed 2’s complement number. Even when
running with a 32 bits machine, the 64 bits representation
is used. If a larger representation is needed, the
Relatifobject might be more appropriate. The Integerobject
is a literal object that belongs to the number class.

     Integerformat
The default literal format for an integer is the decimal
notation. The minus sign (without blank) indicates a
negative number. Hexadecimal and binary notations can also
be used with prefix 0xand 0b. The underscore character can
be used to make the notation more readable.

const a  123
trans b ‐255
const h  0xff
const b  0b1111_1111

Integer number are constructed from the literal notation or
by using an explicit integer instance. The Integerclass
offers standard constructors. The default constructor
creates an integer object and initialize it to 0. The other
constructors take either an integer, a real number, a
character or a string.

const a (Integer)
const b (Integer 2000)
const c (Integer "23")

When the hexadecimal or binary notation is used, care should
be taken to avoid a negative integer. For example,
0x_8000_0000_0000_0000is the smallest negative number. This
number exhibits also the strange property to be equal to its
negation since with 2’s complement, there is no positive
representation.

     Integerarithmetic
Standard arithmetic operators are available as built‐in
operators. The usual addition +, multiplication *and
division /operate with two arguments. The subtraction
‐operates with one or two arguments.

+ 3 4
‐ 3 4
‐ 3
* 3 4
/ 4 2

As a built‐in object, the Integerobject offers various
methods for built‐in arithmetic which directly operates on
the object. The following example illustrates these methods.










                            ‐25‐


trans i 0
i:++
i:‐‐
i:+ 4
i:= 4
i:‐ 1
i:* 2
i:/ 2
i:+= 1
i:‐= 1
i:*= 2
i:/= 2

As a side effect, these methods allows a const symbol to be
modified. Since the methods operates on an object, they do
not modify the state of the symbol. Such methods are called
mutable methods.

const i 0
i:= 1


     Integercomparison
The comparison operators works the same. The only difference
is that they always return a Booleanresult. The comparison
operators are namely equal ==, not equal !=, less than <,
less equal <=, greater >and greater equal >=. These
operators take two arguments.

== 0 1
!= 0 1

Like the arithmetic methods, the comparison operators are
supported as object methods. These methods return a
Booleanobject.

i:=  1
i:== 1
i:!= 0


     Integercalculus
Armed with all these functions, it is possible to develop a
battery of functions operating with numbers. As another
example, we revisit the Fibonacci sequence as demonstrated
in the introduction chapter. Such example was terribly slow,
because of the double recursion. Another method suggested by
Springer and Friedman uses two functions to perform the same
job.

const fib‐it (gamma (n acc1 acc2) (
    if (== n 1) acc2 (fib‐it (‐ n 1) acc2 (+ acc1 acc2))))
const fiboi (gamma (n) (
    if (== n 0) 0 (fib‐it n 0 1)))









                            ‐26‐


This later example is by far much faster, since it uses only
one recursion. Although, it is no the fastest way to write
it, it is still an elegant way to write complex functions.

     methodsOtherInteger
The Integerclass offers other convenient methods. The odd‐
pand even‐pare predicates. The modtake one argument and
returns the modulo between the calling integer and the
argument. The absmethods returns the absolute value of the
calling integer.

i:even‐p
i:odd‐p
i:mod 2
i:= ‐1
i:abs
i:to‐string

The Integerobject is a literal objectand a number object. As
a literal object, the to‐stringand to‐literalmethods are
provided to obtain a string representation for the integer
object. Although the to‐stringmethod returns a string
representation of the calling integer, the to‐literalmethod
returns a parsable string. Strictly speaking for an integer,
there is no difference between a string representation and a
literal representation. However, this is not true for other
objects.

(axi) const i 0x123
(axi) println (i:to‐string)
291
(axi) println (i:to‐literal)
291

As a number object, the integer number can also be
represented in hexadecimal format. The to‐hexaand to‐hexa‐
strignmethods are designed to obtained such representation.
In the first form, the to‐hexamethod return a literal
hexadecimal string representation with the appropriate
prefix while the second one does not.

(axi) const i 0x123
(axi) println (i:to‐hexa)
0x123
(axi) println (i:to‐hexa‐string)
123


     Relatifnumber
A relatifor big number is an integer with infinite
precision. The Relatifclass is similar to the Integerclass
except that it works with infinitely long number. The
relatif notation uses a ror Rsuffix to express a relatif
number versus an integer one. The Relatifobject is a literal









                            ‐27‐


object that belongs to the number class. The predicate
associated with the Relatifobject is relatif‐p.

const a  123R
trans b ‐255R
const c  0xffR
const d  0b1111_1111R
const e (Relatif)
const f (Relatif 2000)
const g (Relatif "23")


     Relatifoperations
Most of the Integerclass operations are supported by the
Relatifobject. The only difference is that there is no
limitation on the number size. This naturally comes with a
computational price. An amazing example is to compute the
biggest know prime Mersenne number. The world record
exponent is 6972593. The number is therefore:

const i 1R
const m (‐ (i:shl 6972593) 1)

This number has 2098960 digits. You can use the
printlnmethod if you wish, but you have been warned...

     Realnumber
The realclass implements the representation for floating
point number. The internal representation is machine
dependent, and generally follows the double representation
with 64 bits as specified by the IEEE 754‐1985 standard for
binary floating point arithmetic. All integer operations are
supported for real numbers. The Realobject is a literal
object that belongs to the number class.

     Realformat
The parser supports two types of literal representation for
real number. The first representation is the dotted
decimalnotation. The second notation is the scientific
notation.

const a  123.0 # a positive real
const b ‐255.5 # a negative real
const c  2.0e3 # year 2000.0

Real number are constructed from the literal notation or by
using an explicit real instance. The Realclass offers
standard constructors. The default constructor creates a
real number object and initialize it to 0.0. The other
constructors takes either an integer, a real number, a
character or a string.

     Realarithmetic
The real arithmetic is similar to the integer one. When an









                            ‐28‐


integer is added to a real number, that number is
automatically converted to a real. Ultimately, a pure
integer operation might generate a real result.

+ 1999.0 1   # 2000.0
+ 1999.0 1.0 # 2000.0
‐ 2000.0 1   # 1999.0
‐ 2000.0 1.0 # 1999.0
* 1000 2.0   # 2000.0
* 1000.0 2.0 # 2000.0
/ 2000.0 2   # 1000.0
/ 2000.0 2.0 # 1000.0

Like the Integerobject, the Realobject has arithmetic built‐
in methods.

trans  r 0.0 # 0.0
r:++       # 1.0
r:‐‐       # 0.0
r:+ 4.0    # 4.0
r:= 4.0    # 4.0
r:‐ 1.0    # 3.0
r:* 2.0    # 8.0
r:/ 2.0    # 2.0
r:+= 1.0   # 5.0
r:‐= 1.0   # 4.0
r:*= 2.0   # 8.0
r:/= 2.0   # 4.0


     Realcomparison
The comparison operators works as the integer one. As for
the other operators, an implicit conversion between an
integer to a real is done automatically.

== 2000 2000   # true
!= 2000 1999   # true

Comparison methods are also available for the Realobject.
These methods take either an integer or a real as argument.

r:=  1.0 # 1.0
r:== 1.0 # true
r:!= 0.0 # true


     exampleAcomplex
One of the most interesting point with functional
programming language is the ability to create complex
function. For example let’s assume we wish to compute the
value at a point xof the Legendre polynomial of order n. One
of the solution is to encode the function given its order.
Another solution is to compute the function and then compute
the value.









                            ‐29‐


# legendre polynomial order 0 and 1
const lp‐0 (gamma (x) 1)
const lp‐1 (gamma (x) x)
# legendre polynomial of order n
const lp‐n (gamma (n) (
    if (> n 1) {
      const lp‐n‐1 (lp‐n (‐ n 1))
      const lp‐n‐2 (lp‐n (‐ n 2))
      gamma (x) (n lp‐n‐1 lp‐n‐2)
      (/ (‐ (* (* (‐ (* 2 n) 1) x)
            (lp‐n‐1 x))
          (* (‐ n 1) (lp‐n‐2 x))) n)
    } (if (== n 1) lp‐1 lp‐0)
  ))
# generate order 2 polynomial
const lp‐2 (lp‐n 2)
# print lp‐2 (2)
println "lp2 (2) = " (lp‐2 2)

Note that the computation can be done either with integer or
real numbers. With integers, you might get some strange
results anyway, but it will work. Note also how the closed
variable mechanism is used. The recursion capture each level
of the polynomial until it is constructed. Note also that we
have here a double recursion.

     methodsOtherreal
The real numbers are delivered with a battery of functions.
These include the trigonometric functions, the logarithm and
couple others. Hyperbolic functions like sinh, cosh, tanh,
asinh, acoshand atanhare also supported. The square root
sqrtmethod return the square root of the calling real. The
floorand ceilingreturns respectively the floor and the
ceiling of the calling real.

const r0 0.0       # 0.0
const r1 1.0       # 1.0
const r2 2.0       # 2.0
const rn ‐2.0      # ‐2.0
const rq (r2:sqrt) # 1.414213
const pi 3.1415926 # 3.141592
rq:floor           # 1.0
rq:ceiling         # 2.0
rn:abs             # 2.0
r1:log             # 0.0
r0:exp             # 1.0
r0:sin             # 0.0
r0:cos             # 1.0
r0:tan             # 0.0
r0:asin            # 0.0
pi:floor           # 3.0
pi:ceiling         # 4.0











                            ‐30‐


     formattingAccuracyand
Real numbers are not necessarily accurate, nor precise. The
accuracy and precision are highly dependent on the hardware
as well as the nature of the operation being performed. In
any case, never assume that a real value is an exact one.
Most of the time, a real comparison will fail, even if the
numbers are very close together. When comparing real
numbers, it is preferable to use the ?=operator. Such
operator result is bounded by the internal precision
representation and will generally return the desired value.
The real precision is an interpreter value which is set with
the set‐absolute‐precisionmethod while the get‐absolute‐
precisionreturns the interpreter precision. There is also a
set‐relative‐precisionand get‐relative‐precisionmethods used
for the definition of relative precision. By default, the
absolute precision is set to 0.00001 and the relative
precision is set to 1.0E‐8.

interp:set‐absolute‐precision 0.0001
const r 2.0
const s (r:sqrt) # 1.4142135
(s:?= 1.4142)    # true

Real number formatting is another story. The formatmethod
takes a precision argumentwhich indicates the number of
digits to print for the decimal part. Note that the format
command might round the result as indicated in the example
below.

const pi 3.1415926535
pi:format 3  # 3.142

If additional formatting is needed, the Stringfill‐leftand
fill‐rightmethods can be used.

const pi  3.1415926535        # 3.1415926535
const val (pi:format 4)       # 3.1416
println (val:fill‐left ’0’ 9) # 0003.1416


     Numberobject
The Integer, Relatifand Realobjects are all derived from the
Numberobject which is a Literalobject. As such, the
predicate number‐pis the right mechanism to test an object
for a number. The class also provides the basic mechanism to
format the number as a string. For integer and relatif, the
hexadecimal representation can be obtained by the to‐hexaand
to‐hexa‐stringmethods. For integer and real numbers, the
formatmethod adjusts the final representation with the
precision argument as indicated before. It is worth to note
that a formatted integer gets automatically converted into a
real representation.











                            ‐31‐


     Character
The Characterobject is another built‐in object. A character
is internally represented by a quad by using a 31 bit
representation as specified by the Unicode standard and ISO
10646.

     Characterformat
The standard quote notation is used to represent a
character. In that respect, there is hare a substantial
difference with other functional language where the quote
protect a form.

const LA01 ’a’ # the character a
const ND10 ’0’ # the digit 0

All characters from the Unicode codesetare supported by the
AFNIX engine. The characters are constructed from the
literal notation or by using an explicit character instance.
The Characterclass offers standard constructors. The default
constructor creates a null character. The other constructors
take either an integer, a character or a string. The string
can be either a single quoted character or the literal
notation based on the U+notation in hexadecimal. For
example, U+40is the @character while U+3A3is the sigma
capital letter.

const nilc (Character)        # null character
const a    (Character ’a’)    # a
const 0    (Character 48)     # 0
const mul  (Character "*")    # *
const div  (Character "U+40") # @


     Characterarithmetic
A character is like an integer, except that it operates in
the range 0 to 0x7FFFFFFF. The character arithmetic is
simpler compared to the integer one and no overflow or
underflow checking is done. Note that the arithmetic
operations take an integer as an argument.

+ ’a’ 1 # ’b’
‐ ’9’ 1 # ’8’

Several Characterobject methods are also provided for
arithmetic operations in a way similar to the Integerclass.

trans  c ’a’ # ’a’
c:++         # ’b’
trans  c ’9’ # ’9’
c:‐‐         # ’8’
c:+ 1        # ’9’
c:‐ 9        # ’0’











                            ‐32‐


     Charactercomparison
Comparison operators are also working with the
Characterobject. The standard operators are namely equal ==,
not equal !=, less than <, less equal <=, greater >and
greater equal >=. These operators take two arguments.

== ’a’ ’b’ # false
!= ’0’ ’1’ # true


     methodsOthercharacter
The Characterobject comes with additional methods. These are
mostly conversion methods and predicates. The to‐
stringmethod returns a string representation of the calling
character. The to‐integermethod returns an integer
representation the calling character. The predicates are
alpha‐p, digit‐p, blank‐p, eol‐p, eos‐pand nil‐p.

const LA01 ’a’  # ’a’
const ND10 ’0’  # ’0’
LA01:to‐string  # "a"
LA01:to‐integer # 97
LA01:alpha‐p    # true
ND10:digit‐p    # true


     String
The Stringobject is one of the most important built‐in
object in the  AFNIX engine. Internally, a string is a
vector of Unicode characters. Because a string operates with
Unicode characters, care should be taken when using
composing characters.

     Stringformat
The standard double quote notation is used to represent
literally a string. Standard escape sequences are also
accepted to construct a string.

const hello "hello"

Any literal object can be used to construct a string. This
means that integer, real, boolean or character objects are
all valid to construct strings. The default constructor
creates a null string. The string constructor can also takes
a string.

const nils (String)      # ""
const one  (String 1)    # "1"
const a    (String ’a’)  # "a"
const b    (String true) # "true"


     Stringoperations
The Stringobject provides numerous methods and operators.









                            ‐33‐


The most common ones are illustrated in the example below.
The lengthmethods returns the total number of characters in
the string object. It is worth to note that this number is
not necessarily the number of printed characters since some
characters might be combining charactersused, for example,
as diacritics. The non‐combining‐lengthmethod might be more
adapted to get the number of printable characters.

const h "hello"
h:length       # 5
h:get 0        # ’h’
h:== "world"   # false
h:!= "world"   # true
h:+= " world"  # "hello world"

The sub‐leftand sub‐rightmethods return a sub‐string, given
the position index. For sub‐left, the index is the
terminating index, while sub‐rightis the starting index,
counting from 0.

# example of sub‐left method
const msg "hello world"
msg:sub‐left  5 # "hello"
msg:sub‐right 6 # "world"

The strip, strip‐leftand strip‐rightare methods used to
strip blanks and tabs. The stripmethod combines both strip‐
leftand strip‐right.

# example of strip method
const str " hello world "
println (str:strip) # "hello world"

The splitmethod returns a vector of strings by splitting the
string according to a break sequence. By default, the break
sequence is the blank, tab and newline characters. The break
sequence can be one or more characters passed as one single
argument to the method.

# example of split method
const str "hello:world"
const vec (str:split ":" # "hello" "world")
println (vec:length) # 2

The fill‐leftand fill‐rightmethods can be used to fill a
string with a character up to a certain length. If the
string is longer than the length, nothing happens.

# example of fill‐left method
const pi  3.1415926535  # 3.1415926535
const val (pi:format 4) # 3.1416
val:fill‐left ’0’ 9     # 0003.1416











                            ‐34‐


     Conversionmethods
The case conversion methods are the standard to‐upperand to‐
lowermethods. The method operates with the internal Unicode
database. As a result, the conversion might change the
string length. Other conversion methods related to the
Unicode representation are also available. These are rather
technical, but can be used to put the string in a normal
form which might be suitable for comparison. Such conversion
always uses the Unicode database normal form representation.

# example of case conversion
const str "hello world"
println (str:to‐upper) # HELLO WORLD


     valueStringhash
The hashidmethod is a method that computes the hash value of
a string. The value depends on the target machine and will
change between a 32 bits and a 64 bits machine. Example
example 0203.alsillustrates the computation of a hash value
for our favorite test string.

# test our favorite string
const hello "hello world"
hello:hashid # 1054055120

The algorithm used by the engine is shown as an example
below. As a side note, it is recommended to print the shift
amount in the program. One may notice, that the value
remains bounded by 24. Since we are xoringthe final value,
it does illustrate that the algorithm is design for a 32
bits machine. With a 64 bits machine the algorithm is
slightly modified to use the extra space. This also means
that the hashid value is not portable across platforms.

# compute string hashid
const hashid (s) {
  const len (s:length)
  trans cnt 0
  trans val 0
  trans sht 17
  do {
    # compute the hash value
    trans i (Integer (s:get cnt))
    val:= (val:xor (i:shl sht))
    # adjust shift index
    if (< (sht:‐= 7) 0) (sht:+= 24)
  } (< (cnt:++) len)
  eval val
}


     Regularexpression
A regular expression or regexis a special literal object









                            ‐35‐


designed to describe a character string in a compact form
with regular patterns. A regular expression provides a
convenient way to perform pattern matching and filed
extraction within a character string.

     Regexsyntax
A regular expression is defined with a special Regexobject.
A regular expression can be built implicitly or explicitly
with the use of the Regexobject. The regex syntax uses the
[and ]characters as block delimiters. When used in a source
file, the parser automatically recognizes a regex and built
the object accordingly. The following example shows two
equivalent methods for the same regex expression.

# syntax built‐in regex
(== [$d+] 2000)         # true
# explicit built‐in regex
(== (Regex "$d+") 2000) # true

In its first form, the [and ]characters are used as syntax
delimiters. The lexical analyzer automatically recognizes
this token as a regex and built the equivalent Regexobject.
The second form is the explicit construction of the
Regexobject. Note also that the [and ]characters are also
used as regex block delimiters.

     andRegexcharacters
Any character, except the one used as operators can be used
in a regex. The $character is used as a meta‐character ‐‐ or
control character ‐‐ to represent a particular set of
characters. For example, [hello world]is a regex which match
only the "hello world"string. The [$d+]regex matches one or
more digits. The following meta characters are built‐in in
the regex engine.

Character   Description
$a          matches any letter or digit
$b          matches any blank characters
$c          matches any combining alphanumeric
$d          matches any digit
$e          matches eol, cr and eos
$l          matches any lower case letter
$n          matches eol or cr
$s          matches any letter
$u          matches any upper case letter
$v          matches any valid afnix constituent
$w          matches any word constituent
$x          matches any hexadecimal characters


The uppercase version is the complement of the corresponding
lowercase character set.  A character which follows a
$character and that is not a meta character is treated as a
normal character. For example $[is the [character. A quoted









                            ‐36‐


string can be used to define character matching which could
otherwise be interpreted as control characters or operator.
A quoted string also interprets standard escaped
sequencesbut not meta characters.

(== [$d+]   2000) # true
(== ["$d+"] 2000) # false

Combining alphanumerical characters can generate surprising
result when used with Unicode string. Combining alphanumeric
characters are alphanumeric characters and non spacing
combining mark as defined by the Unicode consortium. In
practice, the combining marks are the diacritics used with
regular letter, such like the accents found in the western
languages. Because the writing system uses a canonical
decomposition for representing the Unicode string, it turns
out that the printed string is generally represented with
more bytes, making the string length longer than it appears.

     setRegexcharacter
A character set is defined with the <and >characters. Any
enclosed character defines a character set. Note that meta
characters are also interpreted inside a character set. For
example, <$d+‐>represents any digit or a plus or minus. If
the first character is the ^character in the character set,
the character set is complemented with regards to its
definition.

     andRegexblocks
The [and ]characters are the regex sub‐expressions
delimiters. When used at the top level of a regex
definition, they can identify an implicit object. Their use
at the top level for explicit construction is optional. The
following example is strictly equivalent.

# simple real number check
const real‐1 (Regex "$d*.$d+")
# another way with [] characters
const real‐2 (Regex "[$d*.$d+]")

Sub‐expressions can be nested ‐‐ that’s their role ‐‐ and
combined with operators. There is no limit in the nesting
level.

# pair of digit testing
(== [$d$d[$d$d]+] 2000)  # true
(== [$d$d[$d$d]+] 20000) # false

The following unary operators can be used with single
character, control characters and sub‐expressions.

Operator   Description
*          match 0 or more times










                            ‐37‐


+          match 1 or more times
?          match 0 or 1 time
|          alternation


Alternation is an operator which work with a secondary
expression. Care should be taken when writing the right sub‐
expression. For example the following regex [$d|hello]is
equivalent to [[$d|h]ello]. In other word, the minimal first
sub‐expression is used when compiling the regex.

     Grouping
Groups of sub‐expressions are created with the (and
)characters. When a group is matched, the resulting sub‐
string is placed on a stack and can be used later. In this
respect, the regex engine can be used to extract sub‐
strings. The following example extracts the month, day and
year from a particular date format:
[($d$d):($d$d):($d$d$d$d)]. This regex assumes a date in the
form mm:dd:yyyy.

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

Grouping is the mechanism to retrieve sub‐strings when a
match is successful. If the regex is bound to a symbol, the
getmethod can be used to get the sub‐string by index.

     Regexobject
Although a regex can be built implicitly, the Regexobject
can also be used to build a new regex. The argument is a
string which is compiled during the object construction. A
Regexobject is a literal object. This means that the to‐
stringmethod is available and that a call to the
printlnspecial form will work directly.

const   re (Regex "$d+")
println re           # $d+
println re:to‐string # [$d+]


     Regexoperators
The ==and !=operators are the primary operators to perform a
regex match. The ==operator returns trueif the regex matches
the string argument from the beginning to the end of string.
Such operator implies the begin and end of string anchoring.
The <operator returns true if the regex matches the string
or a sub‐string or the string argument.

     Regexmethods
The primary regex method is the getmethod which returns by
index the sub‐string when a group has been matched. The









                            ‐38‐


lengthmethod returns the number of group match.

if (== (const re [($d$d):($d$d)]) "12:31") {
  re:length # 2
  re:get 0  # 12
  re:get 1  # 31
}

The matchmethod returns the first string which is matched by
the regex.

const regex [$d+]
regex:match "Happy new year 2000" # 2000

The replacemethod any occurrence of the matching string with
the string argument.

const regex [$d+]
regex:replace "Hello year 2000" "3000" # hello year 3000


     Argumentconversion
The use of the Regexoperators implies that the arguments are
evaluated as literal object. For this reason, an implicit
string conversion is made during such operator call. For
example, passing the integer 12or the string "12"is strictly
equivalent. Care should be taken when using this implicit
conversion with real numbers.

This chapter covers the standard container objects and more
specifically, iterableobjects such like Cons, Listand
Vector. Special objects like Fifo, Queueand Bitsetare
treated at the end of this chapter. Although the name
container is sufficient enough to describe the object
functionality, it is clear that a container is more than a
simple object reservoir. In particular, the choice of a
container object is often associated to the underlying
algorithm used to store the object. For example, a vector is
appropriate when storing by index is important. If the order
of storage must be preserved, then a fifo object might be
more appropriate. In any case, the choice of a container is
always a question of compromise, so is the implementation.

     Consobject
Originally, a Consobject or cons cellhave been the
fundamental object of the Lisp or Scheme machine. The cons
cell is the building block for list and is similar in some
respect to the cons cellfound in traditional functional
programming language. A Consobject is a simple element used
to build linked list. The cons cell holds an object and a
pointer to the next cons cell. The cons cell object is
called carand the next cons cell is called the cdr. This
original Lisp notation is maintained here for the sake of
tradition. Although a cons cell is the building block for









                            ‐39‐


single linked list, the cell itself is not a list object.
When a list object is needed, the Listdouble linked list
object might be more appropriate.

     constructorsConscell
The default constructor creates a cons cell those car is
initialized to the nil object. The constructor can also take
one or several objects.

const nil‐cons (Cons)
const lst‐cons (Cons 1 ’a’ "hello")

The constructor can take any kind of objects. When all
objects have the same type, the result list is said to be
homogeneous. If all objects do not have the same type, the
result list is said to be heterogeneous. List can also be
constructed directly by the parser. Since all internal forms
are built with cons cell, the construction can be achieved
by simply protectingthe form from being interpreted.

const blist (protect ((1) ((2) ((3)))))


     methodsConscell
A Consobject provides several methods to access the carand
the cdrof a cons cell. Other methods allows access to a list
by index.

const c (Cons "hello" "world")
c:length   # 2
c:get‐car  # "hello"
c:get‐cadr # "world"
c:get 0    # "hello"
c:get 1    # "world"

The set‐carmethod set the car of the cons cell. The
addmethod adds a new cons cell at the end of the cons list
and set the car with the specified object.

     Listobject
The Listobject provides the facility of a double‐link list.
The Listobject is another example of iterable object. The
Listobject provides support for forward and backward
iteration.

     Listconstruction
A list is constructed like a cons cell with zero or more
arguments. Unlike the cons cell, the Listcan have a null
size.

const nil‐list (List)
const dbl‐list (List 1 ’a’ "hello")











                            ‐40‐


     Listmethods
The Listobject methods are similar the Consobject. The
addmethod adds an object at the end of the list. The
insertmethod inserts an object at the beginning of the list.

const list (List "hello" "world")
list:length      # 2
list:get 0       # "hello"
list:get 1       # "world"
list:add "folks" # "hello" "world" "folks"


     Vectorobject
The Vectorobject provides the facility of an index array of
objects. The Vectorobject is another example of iterable
object. The Vectorobject provides support for forward and
backward iteration.

     Vectorconstruction
A vector is constructed like a cons cell or a list. The
default constructor creates a vector with 0 objects.

const nil‐vector (Vector)
const obj‐vector (Vector 1 ’a’ "hello")


     Vectormethods
The Vectorobject methods are similar to the Listobject. The
addmethod appends an object at the end of the vector. The
setmethod set a vector position by index.

const vec (Vector "hello" "world")
vec:length          # 2
vec:get 0           # "hello"
vec:get 1           # "world"
vec:add "folks"     # "hello" "world" "folks"
vec:set 0 "bonjour" # "bonjour" "world" "folks"


     Setobject
The Setobject provides the facility of an object container.
The Setobject is another example of iterable object. The
Setobject provides support for forward iteration. One of the
property of a set is that there is only one object
representation per set. Adding two times the same object
results in one object only.

     Setconstruction
A set is constructed like a vector. The default constructor
creates a set with 0 objects.

const nil‐set (Set)
const obj‐set (Set 1 ’a’ "hello")










                            ‐41‐


     Setmethods
The Setobject methods are similar to the Vectorobject. The
addmethod adds an object in the set. If the object is
already in the set, the object is not added. The
lengthmethod returns the number of elements in the set.

const set       (Set "hello" "world")
set:get‐size    # 2
set:add "folks" # "hello" "world" "folks"


     Iteration
When an object is iterable, it can be used with the reserved
keyword for. The forkeyword iterates on one or several
objects and binds associated symbols during each step of the
iteration process. All iterable objects provides also the
method get‐iteratorwhich returns an iterator for a given
object. The use of iterator is justified during backward
iteration, since foronly perform forward iteration.

     Functionmapping
Given a function func, it is relatively easy to apply this
function to all objects of an iterable object. The result is
a list of successive calls with the function. Such function
is called a mapping function and is generally called map.

const map (obj func) {
  trans result (Cons)
  for (car) (obj) (result:link (func car))
  eval result
}

The linkmethod differs from the addmethod in the sense that
the object to append is set to the cons cell car if the car
and cdr is nil.

     Multipleiteration
Multiple iteration can be done with one call to for. The
computation of a scalar product is a simple but illustrative
example.

# 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
}

Note that the function scalar‐productdoes not make any
assumption about the object to iterate. One could compute
the scalar product between a vector a list for example.

const u (Vector 1 2 3)
const v (List   2 3 4)









                            ‐42‐


scalar‐product u v


     iterableConversionof
The use of an iterator is suitable for direct conversion
between one object and another. The conversion to a vector
can be simply defined as indicted below.

# convert an iterable object to a vector
const to‐vector (obj) {
  trans result (Vector)
  for (i) (obj) (result:add i)
  eval result
}


     Explicititerator
An explicit iterator is constructed with the get‐
iteratormethod. At construction, the iterator is reset to
the beginning position. The get‐objectmethod returns the
object at the current iterator position. The nextadvances
the iterator to its next position. The valid‐pmethod returns
trueif the iterator is in a valid position. When the
iterator supports backward operations, the prevmethod move
the iterator to the previous position. Note that Consobjects
do not support backward iteration. The beginmethod reset the
iterator to the beginning. The endmethod moves the iterator
the last position. This method is available only with
backward iterator.

# reverse a list
const reverse‐list (obj) {
  trans result (List)
  trans itlist (obj:get‐iterator)
  itlist:end
  while (itlist:valid‐p) {
    result:add (itlist:get‐object))
  itlist:prev
}
eval result
}


     SpecialObjects
The engine incorporates other container objects. To name a
few, such objects are the Queue, Bitsetor Fifoobjects.

     Queueobject
A queueis a special object which acts as container with a
fifo policy. When an object is placed in the queue, it
remains there until it has been dequeued. The Fifoand
Queueobjects are somehow similar, with the fundamental
difference that the queue resize itself if needed.










                            ‐43‐


# create a queue with objects
const q (Queue "hello" "world")
q:empty‐p # false
q:length  # 2
# dequeue some object
q:dequeue # hello
q:dequeue # world
q:empty‐p # true


     Bitsetobject
A bit setis a special container for bit. A bit set can be
constructed with a specific size. When the bit set is
constructed, each bit can be marked and tested by index.
Initially, the bitset size is null.

# create a bit set by size
const bs (Bitset 8)
bitset‐p bs # true
# check, mark and clear
assert false (bs:marked‐p 0)
bs:mark 0
assert true  (bs:marked‐p 0)
bs:clear 0
assert false (bs:marked‐p 0)


This chapter covers the class model and its associated
operations. The class model is slightly different compared
to traditional one because dynamic symbol bindings do not
enforce to declare the class data members. A class is an
object which can be manipulated by itself. Such class is
said to belongs to a group of meta classas described later
in this chapter. Once the class concept has been detailed,
the chapter moves to the concept of instance of that class
and shows how instance data members and functions can be
used. The chapter terminates with a description of dynamic
class programming.

     Classobject
A class objectis simply a nameset which can be replicated
via a construction mechanism. A class is created with the
special form class. The result is an object of type
Classwhich supports various symbol binding operations.

     andClassdeclaration
A new class is an object created with the reserved keyword
class. Such class is an object which can be bound to a
symbol.

const Color (class)

Because a class acts like a nameset, it is possible to bind
directly symbols with the qualified namenotation.









                            ‐44‐


const Color (class)
const Color:RED‐FACTOR   0.75
const Color:BLUE‐FACTOR  0.75
const Color:GREEN‐FACTOR 0.75

When a data is defined in the class nameset, it is common to
refer it as a class data member. A class data member is
invariant over the instance of that class. When the data
member is declared with the constreserved keyword, the
symbol binding is in the class nameset.

     bindingClassclosure
A lambda or gamma expression can be define for a class. If
the class do not reference an instance of that class, the
resulting closure is called a class methodof that class.
Class methods are invariant among the class instances. The
standard declaration syntax for a lambda or gamma expression
is still valid with a class.

const Color:get‐primary‐by‐string (color value) {
  trans val "0x"
  val:+= (switch color (
      ("red"   (value:substr 1 3))
      ("green" (value:substr 3 5))
      ("blue"  (value:substr 5 7))
    ))
  Integer val
}

The invocation of a class method is done with the standard
qualified namenotation.

Color:get‐primary‐by‐string "red"   "#23c4e5"
Color:get‐primary‐by‐string "green" "#23c4e5"
Color:get‐primary‐by‐string "blue"  "#23c4e5"


     accessClasssymbol
A class acts as a nameset and therefore provides the
mechanism to evaluate any symbol with the qualified name
notation.

const Color:RED‐VALUE "#ff0000"
const Color:print‐primary‐colors (color) {
  println "red   color " (
    Color:get‐primary‐color "red"   color)
  println "green color " (
    Color:get‐primary‐color "green" color)
  println "blue  color " (
    Color:get‐primary‐color "blue"  color)
}
# print the color components for the red color
Color:print‐primary‐colors Color:RED‐VALUE










                            ‐45‐


     Instance
An instanceof a class is an object which is constructed by a
special class method called a constructor. If an instance
constructor does not exist, the instance is said to have a
default construction. An instance acts also as a nameset.
The only difference with a class, is that a symbol
resolution is done first in the instance nameset and then in
the instance class. As a consequence, creating an instance
is equivalent to define a default nameset hierarchy.

     Instanceconstruction
By default, a instance of the class is an object which
defines an instance nameset. The simplest way to define an
anonymous instance is to create it directly.

const i     ((class))
const Color (class)
const red   (Color)

The example above define an instance of an anonymous class.
If a class object is bound to a symbol, such symbol can be
used to create an instance of that class. When an instance
is created, the special symbol named thisis defined in the
instance nameset. This symbol is bounded to the instance
object and can be used to reference in an anonymous way the
instance itself.

     Instanceinitialization
When an instance is created, the engine looks for a special
lambda expression called preset. This lambda expression, if
it exists, is executed after the default instance has been
constructed. Such lambda expression is a method since it can
refer to the thissymbol and bind some instance symbols. The
arguments which are passed during the instance construction
are passed to the presetmethod.

const Color (class)
trans Color:preset (red green blue) {
  const this:red   (Integer red)
  const this:green (Integer green)
  const this:blue  (Integer blue)
}
# create some default colors
const Color:RED   (Color 255   0   0)
const Color:GREEN (Color   0 255   0)
const Color:BLUE  (Color   0   0 255)
const Color:BLACK (Color   0   0   0)
const Color:WHITE (Color 255 255 255)

In the example above, each time a color is created, a new
instance object is created. The constructor is invoked with
the thissymbol bound to the newly created instance. Note
that the qualified name this:reddefines a new symbol in the
instance nameset. Such symbol is sometimes referred as an









                            ‐46‐


instance data member. Note as well that there is no
ambiguity in resolving the symbol red. Once the symbol is
created, it shadows the one defined as a constructor
argument.

     accessInstancesymbol
An instance acts as a nameset. It is therefore possible to
bind locally to an instance a symbol. When a symbol needs to
be evaluated, the instance nameset is searched first. If the
symbol is not found, the class nameset is searched. When an
instance symbol and a class symbol have the same name, the
instance symbol is said to shadow the class symbol. The
simple example below illustrates this property.

const c   (class)
const c:a 1
const i   (c)
const j   (c)
const i:a 2
# class symbol access
println   c:a
# shadow symbol access
println   i:a
# non shadow access
println   j:a

When the instance is created, the special symbol metais
bound in the instance nameset with the instance class
object. This symbol can therefore be used to access a shadow
symbol.

const c   (class)
const i   (c)
const c:a 1
const i:a 2
println   i:a
println   i:meta:a

The symbol metamust be used carefully, especially inside an
initialization since it might create an infinite recursion
as shown below.

const c (class)
trans c:preset nil (const i (this:meta))
const i (c)


     Instancemethod
When lambda expression is defined within the class or the
instance nameset, that lambda expression is callable from
the instance itself. If the lambda expression uses the
thissymbol, that lambda is called an instance method since
the symbol thisis defined in the instance nameset. If the
instance method is defined in the class nameset, the









                            ‐47‐


instance method is said to be global, that is, callable by
any instance of that class. If the method is defined in the
instance nameset, that method is said to be localand is
callable by the instance only. Due to the nature of the
nameset parent binding, only lambda expression can be used.
Gamma expressions will not work since the gamma nameset has
always the top level nameset as its parent one.

const Color (class)
# class constructor
trans Color:preset (red green blue) {
  const this:red   (Integer red)
  const this:green (Integer green)
  const this:blue  (Integer blue)
}
const Color:RF 0.75
const Color:GF 0.75
const Color:BF 0.75
# this method returns a darker color
trans Color:darker nil {
  trans lr (Integer (max (this:red:*   Color:RF) 0))
  trans lg (Integer (max (this:green:* Color:GF) 0))
  trans lb (Integer (max (this:blue:*  Color:BF) 0))
  Color lr lg lb
}
# get a darker color than yellow
const yellow      (Color 255 255 0)
const dark‐yellow (yellow:darker)


     Instanceoperators
Any operator can be defined at the class or the instance
level. Operators like ==or !=generally requires the ability
to assert if the argument is of the same type of the
instance. The global operator ==will return true if two
classes are the same. With the use of the metasymbol, it is
possible to assert such equality.

# this method checks that two colors are equals
trans Color:== (color) {
  if (== Color color:meta) {
    if (!= this:red   color:red)   (return false)
    if (!= this:green color:green) (return false)
    if (!= this:blue  color:blue)  (return false)
    eval true
  } false
}
# create a new yellow color
const  yellow (Color 255 255 0)
(yellow:== (Color 255 255 0)) # true

The global operator ==returns trueif both arguments are the
same, even for classes. Method operators are left open to
the user.









                            ‐48‐


     exampleComplexnumber
As a final example, a class simulating the behavior of a
complex number is given hereafter. The interesting point to
note is the use of the operators. As illustrated before, the
class uses uses a default method method to initialize the
data members.

# class declaration
const Complex (class)
# constructor
trans Complex:preset (re im) {
  trans this:re (Real re)
  trans this:im (Real im)
}

The constructor creates a complex object with the help of
the real part and the imaginary part. Any object type which
can be bound to a Realobject is acceptable.

# class mutators
trans Complex:set‐re (x) (trans this:re (Real re))
trans Complex:set‐im (x) (trans this:im (Real im))
# class accessors
trans Complex:get‐re nil (Real this:re)
trans Complex:get‐im nil (Real this:im)

The accessors and the mutators simply provides the interface
to the complex number components and perform a cloning of
the calling or returned objects.

# complex number module
trans Complex:module nil {
  trans result (Real (+ (* this:re this:re)
      (* this:im this:im)))
  result:sqrt
}
# complex number formatting
trans Complex:format nil {
  trans result (String this:re)
  result:+= "+i"
  result:+= (String this:im)
}

The moduleand formatare simple methods. Note the the complex
number formatting is arbitrary here.

# complex predicate
const complex‐p (c) (
  if (instance‐p c) (== Complex c:meta) false)

The complex‐ppredicate is the perfect illustration of the
use of the metareserved symbol. However, it shall be noted
that the meta‐comparison is done if and only if the calling
argument is an instance.









                            ‐49‐


# operators
trans Complex:== (c) (
  if (complex‐p c) (and (this:re:== c:re)
    (this:im:== c:im)) (
    if (number‐p c)  (and (this:re:== c)
      (this:im:zero‐p)) false))
trans Complex:= (c) {
  if (complex‐p c) {
    this:re:= (Real c:re)
    this:im:= (Real c:im)
    return this
  }
  this:re:= (Real c)
  this:im:= 0.0
  return this
}
trans Complex:+ (c) {
  trans result (Complex this:re this:im)
  if (complex‐p c) {
    result:re:+= c:re
    result:im:+= c:im
    return result
  }
  result:re:+= (Real c)
  eval result
}

The operators are a little tedious to write. The comparison
can be done with a complex number or a built‐in number
object. The assignation operator creates a copy for both the
real and imaginary part. The summation operator is given
here for illustration purpose.

     Inheritance
Inheritance is the mechanism by which a class or an instance
inherits methods and data member access from a parent
object. The class model is based on a single inheritance
model. When an instance object defines a parent object, such
object is called a super instance. The instance which has a
super instance is called a derived instance. The main
utilization of inheritance is the ability to reuse methods
for that super instance.

     Derivationconstruction
A derived object is generally defined within the
presetmethod of that instance by setting the superdata
member. The superreserved keyword is set to nil at the
instance construction. The good news is that any object can
be defined as a super instance, including built‐in object.

const c (class)
const c:preset nil {
  trans this:super 0
}









                            ‐50‐


In the example above, an instance of class cis constructed.
The super instance is with an integer object. As a
consequence, the instance is derived from the
Integerinstance. Another consequence of this scheme is that
derived instance do not have to be built from the same base
class.

     accessDerivedsymbol
When an instance is derived from another one, any symbol
which belongs to the super instance can be access with the
use of the superdata member. If the super class can evaluate
a symbol, that symbol is resolved automatically by the
derived instance.

const c       (class)
const i       (c)
trans i:a     1
const j       (c)
trans j:super i
println j:a

When a symbol is evaluated, a set of search rules is
applied. The engine gives the priority to the class nameset
vs the super instance. As a consequence, a class data member
might shadow a super instance data member. The rule
associated with a symbol evaluation can be summarized as
follow.
     Look in the instance nameset.
     Look in the class nameset.
     Look in the super instance if it exists.
     Look in the base object.


     Instancere‐parenting
The ability to set dynamically the parent instance make the
object model an ideal candidate to support instance re‐
parenting. In this model, a change in the parent instance is
automatically reflected at the instance method call.

const c (class)
const i (c)
trans i:super 0
println (i:to‐string) # 0
trans i:super "hello world"
println (i:to‐string) # hello world

In this example, the instance is originally set with an
Integerinstance parent. Then the instance is re‐parentedwith
a Stringinstance parent. The call to the to‐stringmethod
illustrates this behavior.

     Instancere‐binding
The ability to set dynamically the instance class is another
powerful feature of the class model. In this approach, the









                            ‐51‐


instance meta class can be changed dynamically with the
mutemethod. Furthermore, it is also possible to create
initially an instance without any class binding, which is
later muted.

# create a point class
const  point (class)
# point class
trans point:preset (x y) {
  trans this:x x
  trans this:y y
}
# create an empty instance
const p (Instance)
# bind the point class
p:mute point 1 2

In this example, when the instance is muted, the
presetmethod is called automatically with the extra
arguments.

     Instanceinference
The ability to instantiate dynamically inferred instance is
offered by the instance model. An instance bis said to be
inferred by the instance awhen the instance ais the super
instance of the instance b. The instance inference is
obtained by binding the infersymbol to a class. When an
instance of that class is created, the inferred instance is
also created.

# base class A
const A  (class)
# inferred class B
const B  (class)
const A:infer B
# create an instance from A
const  x (A)
assert B (x:meta)
assert A (x:super:meta)

In this example, when the instance is created, the inferred
instance is also created and returned by the instantiation
process. The presetmethod is only called for the inferred
instance if possible or the base instance if there is no
inferring class. Because the base presetpreset method is not
called automatically, the inferred method is responsible to
do such call.

trans B:preset (x y) {
  trans this:xb x
  trans this:yb y
  if (== A this:super:meta) (this:super:preset x y)
}










                            ‐52‐


Because the class can mute from one call to another and also
the inferred class, the presetmethod call must be used after
a discrimination of the meta class has been made as
indicated by the above example.

     Instancedeference
In the process of creating instances, one might have a
generic class with a method that attempts to access a data
member which is bound to another class. The concept of class
deferenceis exactly designed for this purpose. With the help
of reserved keyword defer, a class with virtual data member
accessors can be bound to a base class as indicated in the
example below.

# create the base and defer class
const bc (class)
const dc (class)
# bind the base preset method
trans bc:preset nil (const this:y 2)
# bind the defer accessor to the base data member
trans dc:get‐y nil (eval this:y)
# bind the defer class in the base class
const bc:defer dc
# create an instance from the base class
const i (bc)
# access to the base member with the defer method
assert 2 (i:get‐y)

It is worth to note that the class deference is made at the
class level. When an instance of the base class is created,
all methods associated with the deferentclass are visible
from the base class, thus making the deferentclass a virtual
interface to the base class.

This chapter covers advanced concepts of the writing system.
The first subject is the exception model. The second subject
covers some properties of the namesets in the context of the
interpreter object. The thread sub‐system is then described
along with the synchronization mechanism. Finally, some
notes related to the functional system are given at the end
of this chapter.

     Exception
An exceptionis 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.

     exceptionThrowingan
An exception is thrown with the reserved keyword 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









                            ‐53‐


backward in the call stack until an exception handler catch
it.

if (not (number‐p n))
(throw "type‐error" "invalid object found" n)

The example above is the general form to throw an exception.
The first argument is the the exception id. The second
argument is the exception reason. The third argument is the
exception object. The exception id and reason are always a
string. The exception object can be any object which is
carried by the exception. The reserved keyword throwaccepts
0 or more arguments.

throw
throw "type‐error"
throw "type‐error" "invalid argument"

With 0 argument, the exception is thrown with the exception
id set to "user‐exception". With one argument, the argument
is the exception id. With 2 arguments, the exception id and
reason are set. Within a try block, an exception can be
thrown again by using the exception object represented with
the whatsymbol.

try {
  ...
} {
  println "exception caught and re‐thrown"
  throw what
}


     Exceptionhandler
The special form tryexecutes 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")

In its second form, the tryreserved keyword can accept a
second form which is executed when an exception is caught.
When an exception is caught, a new nameset is created and
the special symbol whatis bounded with the exception object.
In such environment, the exception can be evaluated.











                            ‐54‐


Symbol   Description
eid      Exception id
name     Exception file name
line     Exception line number
about    Exception extended reason
reason   Exception reason
object   Exception object



try (throw "hello")
(eval what:eid)
try (throw "hello" "world")
(eval what:reason)
try (throw "hello" "world" 2000)
(eval what:object)

Exceptions are useful to notify abruptly that something went
wrong. With an untyped language, it is also a convenient
mechanism to abort an expression call if some arguments do
not match the expected types.

# protected factorial
const fact (n) {
  if (not (integer‐p n))
  (throw "number‐error" "invalid argument in fact")
  if (== n 0) 1 (* n (fact (‐ n 1)))
}
try (fact 5) 0
try (fact "hello") 0


     Nameset
A nameset is created with the reserved keyword nameset.
Without argument, the namesetreserved keyword creates a
nameset without setting its parent. With one argument, a
nameset is created and the parent set with the argument.

const nset (nameset)
const nset (nameset ...)


     Defaultnamesets
When a nameset is created, the symbol .is automatically
created and bound to the newly created nameset. If a parent
nameset exists, the symbol ..is also automatically created.
The use of the current nameset is a useful notation to
resolve a particular name given a hierarchy of namesets.

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









                            ‐55‐


println a           # 1


     inheritanceNamesetand
When a nameset is set as the super object of an instance,
some interesting results are obtained. Because symbols are
resolved in the nameset hierarchy, there is no limitation to
use a nameset to simulate a kind of multiple inheritance.
The following example illustrates this point.

const   cls (class)
const   ins (cls)
const   ins:super (nameset)
const   ins:super:value 2000
const   ins:super:hello "hello world "
println ins:hello ins:value # hello world 2000


     DelayedEvaluation
The engine provides a mechanism called delayed evaluation.
Such mechanism permits the encapsulation of a form to be
evaluated inside an object called a promise.

     promiseCreatinga
The reserved keyword delaycreates a promise. When the
promise is created, the associated object is not evaluated.
This means that the promise evaluates to itself.

const a (delay (+ 1 2))
promise‐p a # true

The previous example creates a promise and store the
argument form. The form is not yet evaluated. As a
consequence, the symbol aevaluates to the promise object.

     promiseForcinga
The reserved keyword forcethe evaluation of a promise. Once
the promise has been forced, any further call will produce
the same result. Note also that, at this stage, the promise
evaluates to the evaluated form.

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


     Enumeration
Enumeration, that is, named constant bound to an object, can
be declared with the reserved keyword enum. The enumeration
is built with a list of literal and evaluated as is.

const  e    (enum E1 E2 E3)









                            ‐56‐


assert true (enum‐p e)

The complete enumeration evaluates to an Enumobject. Once
built, enumeration item evaluates by literal and returns an
Itemobject.

assert true   (item‐p e:E1)
assert "Item" (e:E1:repr)

Items are comparable objects. Only items can be compared.
For a given item, the source enumeration can be obtained
with the get‐enummethod.

# check for item equality
const i1 e:E1
const i2 e:E2
assert true  (i1:== i1)
assert false (== i1 i2)
# get back the enumeration
assert true (enum‐p (i1:get‐enum))


     Logger
The Loggerclass is a message logger that stores messages in
a buffer with a level. The default level is the level 0. A
negative level generally indicates a warning or an error
message but this is just a convention which is not enforced
by the class. A high level generally indicates a less
important message. The messages are stored in a circular
buffer. When the logger is full, a new message replace the
oldest one. By default, the logger is initialized with a 256
messages capacity that can be re‐sized.

const log    (Logger)
assert true  (logger‐p log)

When a message is added, the message is stored with a time‐
stamp and a level. The time‐stamp is used later to format a
message. The lengthmethod returns the number of logged
messages. The get‐messagemethod returns a message by index.
Because the system operates with a circular buffer, the get‐
messagemethod manages the indexes in such way that the old
messages are accessible with the oldest index. For example,
even after a buffer circulation, the index 0 will point to
the oldest message. The get‐message‐levelreturns the message
level and the get‐message‐timereturns the message posted
time.

const mesg (log:get‐message 0)

In term of usage, the logger facility can be conveniently
used with other derived classes. The standard i/o module
provides several classes that permits to manage logging
operations in a convenient way.









                            ‐57‐


     Interpreter
The interpreter is by itself a special object with
specialized methods which do not have equivalent using the
standard notation. The interpreter is always referred with
the special symbol interp. The following table is a summary
of the symbols and methods bound to the interpreter.

Symbol          Description
argv            Command arguments vector
os‐name         Operating system name
os‐type         Operating system type
version         Full version
loader          The interpreter loader
resolver        The interpreter resolver
afnix‐uri       Official uri name
program‐name    Interpreter program name
major‐version   Major version number
minor‐version   Minor version number
patch‐version   Patch version number
machine‐size    The interpreter machine size



Symbol                   Description
dup                      duplicate the interpreter
roll                     run the interpreter loop
wait                     Wait for normal threads
load                     Load a file and execute it
launch                   Launch a normal thread
daemon                   Launch a daemon thread
library                  Load and initialize a library
read‐line                Get an input stream line
read‐passphrase          Get an input stream passphrase
set‐absolute‐precision   Set absolute precision
set‐relative‐precision   Set relative precision
get‐absolute‐precision   Get absolute precision
get‐relative‐precision   Get relative precision



     Argumentsvector
The interp:argvqualified name evaluates to a vector of
strings. Each argument is stored in the vector during the
interpreter initialization.

zsh> axi hello world
(axi) println (interp:argv:length) # 2
(axi) println (interp:argv:get 0)  # hello


     Interpreterversion
Several symbols can be used to track the interpreter version
and the operating system. The full version is bound to the
interp:versionqualified name. The full version is composed









                            ‐58‐


of the major, minorand patchnumber. The operating system
name is bound to the qualified name interp:os‐name. The
operating system type is bound to the interp:os‐type.

println "major number   : " interp:major‐version
println "minor number   : " interp:minor‐version
println "patch number   : " interp:patch‐version
println "version number : " interp:version
println "system name    : " interp:os‐name
println "system type    : " interp:os‐type
println "official uri   : " interp:afnix‐uri


     Methodload
The interp:loadmethod loads and execute a file. The
interpreter interactive command session is suspended during
the execution of the file. In case of error or if an
exception is raised, the file execution is terminated. The
process used to load a file is governed by the file
resolver. Without extension, a compiled file is searched
first and if not found a source file is searched.

     Methodlibrary
The interp:librarymethod loads and initializes a library.
The interpreter maintains a list of opened library. Multiple
execution of this method for the same library does nothing.
The method returns the library object.

interp:library "afnix‐sys"
println "random number: " (afnix:sys:get‐random)


     Methoddup
The interpreter can be duplicated with the help of the
dupmethod. Without argument, a clone of the current
interpreter is made and a terminal object is attached to it.
When used in conjunction with the rollmethod, this approach
permits to create an interactive interpreter. The dupmethod
also accepts a terminal object.

# duplicate the interpreter
const si (interp:dup)
# change the primary prompt
si:set‐primary‐prompt "(si)"


     Methodroll
The interpreter loop can be run with the roll. The loop
operates by reading the interpreter input stream. If the
interpreter has been cloned with the help of the dupmethod,
this method provides a convenient way to operate in
interactive mode. The method is not called loopbecause it is
a reserved keyword and starting a loop is like having the
ball rolling.









                            ‐59‐


# duplicate the interpreter
const si (interp:dup)
# loop with this interpreter
si:roll


     Methodwait
The interpreter can wait for all normal threads to complete.
When invoked, the interpreter monitors all normal threads
and wait unil the terminate normally. This is a standard
synchronization method in a multithreaded environment.

# create a thread
launch f
# wait for completion
interp:wait


     Librarianobject
A librarian fileis a special file that acts as a containers
for various files. A librarian file is created with the
axl‐‐ cross librarian ‐‐utility. Once a librarian file is
created, it can be added to the interpreter resolver. The
file access is later performed automatically by name with
the standard interpreter loadmethod.

     librarianCreatinga
The axlutility is the preferred way to create a librarian.
Given a set of files, axlcombines them into a single one.

zsh: axl ‐h
usage: axl [options] [files]
[h]      print this help message
[v]      print version information
[c]      create a new librarian
[x]      extract from the librarian
[s]      get file names from the librarian
[t]      report librarian contents
[f] lib  set the librarian file name

The coption creates a new librarian. The librarian file name
is specified with the foption.

zsh: axl ‐c ‐f librarian.axl file‐1.als file‐2.als

The previous command combines file‐1.alsand file‐2.alsinto a
single file called librarian.axl. Note that any file can be
included in a librarian.

     librarianUsingthe
Once a librarian is created, the interpreter ‐ioption can be
used to specify it. The ‐ioption accepts either a directory
name or a librarian file. Once the librarian has been
opened, the interpreter loadmethod can be used as usual.









                            ‐60‐


zsh> axi ‐i librarian.axl
(axi) interp:load "file‐1.als"
(axi) interp:load "file‐2.als"

The librarian acts like a file archive. The interpreter file
resolver takes care to extract the file from the librarian
when the loadmethod is invoked.

     Librariancontents
The axlutility provides the ‐tand ‐soptions to look at the
librarian contents. The ‐soption returns all file name in
the librarian. The ‐toption returns a one line description
for each file in the librarian.

zsh: axl ‐t ‐f librarian.axl
‐‐‐‐‐‐‐‐       1234 file‐1.als
‐‐‐‐‐‐‐‐       5678 file‐2.als

The one line report contains the file flags, the file size
and the file name. The file flags are not used at this time.
One possible use in the future is for example, an auto‐load
bitor any other useful things.

     Librarianextraction
The ‐xoption permits to extract file from the librarian.
Without any file argument, all files are extracted. With
some file arguments, only those specified files are
extracted.

zsh: axl ‐x ‐f librarian.axl
zsh: axl ‐x ‐f librarian.axl file‐1.als


     Librarianobject
The Librarianobject can be used as a convenient way to
create a collection of files or to extract some of them.

     Outputlibrarian
The Librarianobject is a standard object. Its predicate is
librarian‐p. Without argument, a librarian is created in
output mode. With a string argument, the librarian is opened
in input mode, with the file name argument. The output mode
is used to create a new librarian by adding file into it.
The input mode is created to read file from the librarian.

# create a new librarian
const lbr (Librarian)
# add a file into it
lbr:add "file‐1.als"
# write it
lbr:write "librarian.axl"

The addmethod adds a new file into the librarian. The
writemethod the full librarian as a single file those name









                            ‐61‐


is writemethod argument.

     Inputlibrarian
With an argument, the librarian object is created in input
mode. Once created, file can be read or extracted. The
lengthmethod ‐‐ which also work with an output librarian ‐‐
returns the number of files in the librarian. The exists‐
ppredicate returns true if the file name argument exists in
the librarian. The get‐namesmethod returns a vector of file
names in this librarian. The extractmethod returns an input
stream object for the specific file name.

# open a librarian for reading
const lbr (Librarian "librarian.axl")
# get the number of files
println (lbr:length)
# extract the first file
const is (lbr:extract "file‐1.als")
# is is an input stream ‐ dump each line
while (is:valid‐p) (println (is:readln))

Most of the time, the librarian object is used to extract
file dynamically. Because a librarian is mapped into the
memory at the right offset, there is no worry to use big
librarian, even for a small file. Note that any type of file
can be used, text or binaries.

     Fileresolver
The file resolveris a special object used by the interpreter
to resolve file path based on the search path. The resolver
uses a mixed list of directories and librarian files in its
search path. When a file path needs to be resolved, the
search path is scanned until a matched is found. Because the
librarian resolution is integrated inside the resolver,
there is no need to worry about file extraction. That
process is done automatically. The resolver can also be used
to perform any kind of file path resolution.

     Resolverobject
The resolver object is created without argument. The
addmethod adds a directory path or a librarian file to the
resolver. The validmethod checks for the existence of a
file. The lookupmethod returns an input stream object
associated with the object.

# create a new resolver
const rslv (Resolver)
assert true (resolver‐p rslv)
# add the local directory on the search path
rslv:add "."
# check if file test.als exists
# if this is ok ‐ print its  contents
if (rslv:valid‐p "test.als") {
  const is (rslv:lookup "test.als")









                            ‐62‐


  while (is:valid‐p) (println (is:readln))
}


     Threadoperations
The interpreter is a multi‐threaded engine with a native
implementation of objects locking. A thread is started with
the reserved keyword launch. The execution is completed when
all threads have terminated. This means that the master
thread (i.e the first thread) is suspended until all other
threads have completed their execution.

     threadStartinga
A thread is started with the reserved keyword launch. The
form to execute in a thread is the argument. The simplest
thread to execute is the nilthread.

launch (nil)

There exists an alternate mechanism to start a thread with
the reserved keyword launchand a thread object. Such
mechanism is used when using deferred thread object creation
or a thread generator object known as a thread set.

     andThreadobject
When a thread terminate, the thread object holds the result
of the last executed form. The thread object is returned by
the launchcommand. The thread‐ppredicates returns trueif the
object is a thread descriptor.

const thr (launch (nil))
println   (thread‐p thr) # true

The thread result can be obtained with the help of the
resultmethod. Although the result can be accessed at any
time, the returned value will be niluntil the thread as
completed its execution.

const thr (launch (nil))
println   (thr:result)   # nilp

Although the engine will ensure that the result is niluntil
the thread has completed its execution, it does not mean
that it is a reliable approach to test until the result is
not nil. The engine provides various mechanisms to
synchronize a thread and eventually wait for its completion.

     Sharedobjects
The whole purpose of using a multi‐threaded environment is
to provide a concurrent execution with some shared
variables. Although, several threads can execute
concurrently without sharing data, the most common situation
is that one or more global variable are accessed ‐‐ and even
changed ‐‐ by one or more threads. Various scenarios are









                            ‐63‐


possible. For example, a variable is changed by one thread,
the other thread just read its value. Another scenario is
one read, multiple write, or even more complicated, multiple
read and multiple write. In any case, the interpreter
subsystem must ensure that each objects are in a good state
when such operation do occur.The engine provides an
automatic synchronization mechanism for global objects,
where only one thread can modify an object, but several
thread can read it. This mechanism known as read‐write
lockingguarantees that there is only one writer, but
eventually multiple reader. When a thread starts to modify
an object, no other thread are allowed to read or write this
object until the transaction has been completed. On the
opposite, no thread is allowed to change (i.e. write) an
object, until all thread which access (i.e. read) the object
value have completed the transaction. Because a context
switch can occur at any time, the object read‐write locking
will ensure a safe protection during each concurrent access.

     accessSharedprotection
We illustrate the previous discussion with an interesting
example and some variations around it. Let’s consider a form
which increase an integer object and another form which
decrease the same integer object. If the integer is
initialized to 0, and the two forms run in two separate
threads, we might expect to see the value bounded by the
time allocated for each thread. In other word, this simple
example is a very good illustration of your machine
scheduler.

# shared variable access
const var 0
# increase method
const incr nil {
  while true (println "increase: " (var:= (+ var 1)))
}
# decrease method
const decr nil {
  while true (println "decrease: " (var:= (‐ var 1)))
}
# start both threads
launch (decr)
launch (incr)

In the previous example, varis initialized to 0. The
incrthread increments varwhile the decrthread decrements
var. Depending on the operating system, the result stays
bounded within a certain range. The previous example can be
changed by using the main thread or a third thread to print
the variable value. The end result is the same, except that
there is more threads competing for the shared variable.

# shared variable access
const var 0









                            ‐64‐


# incrementer, decrementer and printer
const incr nil (while true (var:= (+ var 1)))
const decr nil (while true (var:= (‐ var 1)))
const prtv nil (while true (println "value = " var))
# start all threads
launch (decr)
launch (incr)
launch (prtv)


     Synchronization
Although, there is 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.

     Formsynchronization
The reserved keyword synccan 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 creates a gamma expression which make
sure that both the error code and error message are printed
in one group, when several threads call it.

     Threadcompletion
The other piece of synchronization is the thread completion
indicator. The thread descriptor contains a method called
waitwhich 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 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 when started in a thread. Note the
use of the waitmethod to make sure the thread has completed









                            ‐65‐


before checking for the flag value. It is also worth to note
that waitis one of the method which guarantees that a thread
result is valid. Another use of the waitmethod 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))


     Completeexample
We illustrate the previous discussion with a complete
example. The idea is to perform a matrix multiplication. A
thread is launched when when multiplying one line with one
column. The result is stored in the thread descriptor. A
vector of thread descriptor is used to store the result.

# initialize the shared library
interp:library "afnix‐sys"
# shared vector of threads descriptors
const thr‐group (Vector)
# waits until all threads in the group are finished
const wait‐all nil (for (thr) (thr‐group) (thr:wait))

The group of threads is represented as a vector. Based on
the the previous discussion, a simple loop that blocks until
all threads are completed is designed as a simple gamma
expression.

# initializes a matrix with random numbers
const init‐matrix (n) {
  trans i (Integer 0)
  const m (Vector)
  do {
    trans v (m:add (Vector))
    trans j (Integer)
    do {
      v:add (afnix:sys:get‐random)
    } (< (j:++) n)
  } (< (i:++) n)
  eval m
}

The matrix initialization is quite straightforward. The
matrix is represented as a vector of lines. Each line is
also a vector of random integer number. It is here worth to
note that the standard mathmodule provides a native
implementation of real matrix.

# this procedure multiply one line with one column
const mult‐line‐column (u v) {
  assert (u:length) (v:length)









                            ‐66‐


  trans result 0
  for (x y) (u v) (result:+= (* x y))
  eval result
}
# this procedure multiply two vectors assuming one
# is a line and one is a column from the matrix
const mult‐matrix (mx my) {
  for (lv) (mx) {
    assert true (vector‐p lv)
    for (cv) (my) {
      assert true (vector‐p cv)
      thr‐group:add (launch (mult‐line‐column lv cv))
    }
  }
}

The matrix vector multiplication is at the heart of the
example. Each line‐column multiplication is started into a
thread and the thread object is placed into the thread group
vector.

# check for some arguments
# note the use of errorln method
if (== 0 (interp:argv:length)) {
  errorln "usage: axi 0607.als size"
  afnix:sys:exit 1
}
# get the integer and multiply
const n (Integer (interp:argv:get 0))
mult‐matrix (init‐matrix n) (init‐matrix n)
# wait for all threads to complete
wait‐all
# make sure we have the right number
assert (* n n) (thr‐group:length)

The main execution is started with the matrix size as the
first argument. Two random matrices are then created and the
multi‐threaded multiplication is launched. The main thread
is blocked until all threads in the thread group are
completed.

     Conditionvariable
A condition variableis another mechanism to synchronize
several threads. A condition variable is modeled with the
Condvarobject. At construction, the condition variable is
initialized to false. A thread calling the waitmethod will
block until the condition becomes true. The markmethod 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 following example shows how the main thread
blocks until another change the state of the condition.

# create a condition variable
const cv (Condvar)









                            ‐67‐


# this function runs in a thread ‐ does some
# computation and mark the condition variable
const do‐something nil {
  # do some computation
  ....
  # mark the condition
  cv:mark
}
# start some computation in a thread
launch (do‐something)
# block until the condition is changed
cv:wait‐unlock
# continue here

In this example, the condition variable is created at the
beginning. The thread is started and the main thread blocks
until the thread change the state of the condition variable.
It is important to note the use of the wait‐unlockmethod.
When the main thread is re‐started (after the condition
variable has been marked), the main thread owns the lock
associated with the condition variable. The wait‐
unlockmethod unlocks that lock when the main thread is
restarted. Note also that the wait‐unlockmethod reset the
condition variable. if the waitmethod was used instead of
wait‐unlockthe lock would still be owned by the main thread.
Any attempt by other thread to call the mark method would
result in the calling thread to block until the lock is
released.The Condvarclass has several methods which can be
used to control the behavior of the condition variable. Most
of them are related to lock control. The resetmethod reset
the condition variable. The lockand unlockcontrol the
condition variable locking. The mark, waitand wait‐
unlockmethod controls the synchronization among several
threads.

     Functionexpression
A lambda expression or a gamma expression can be seen like a
function object with no name. During the evaluation process,
the expression object is evaluated as well as the arguments
‐‐ from left to right ‐‐ and a result is produced by
applying those arguments to the function object. An
expression can be built dynamically as part of the
evaluation process.

(axi) println ((lambda (n) (+n 1)) 1)
2

The difference between a lambda expression and a gamma
expression is only in the nameset binding during the
evaluation process. The lambda expression nameset is linked
with the calling one, while the gamma expression nameset is
linked with the top level nameset. The use of gamma
expression is particularly interesting with recursive
functions as it can generate a significant execution









                            ‐68‐


speedup. The previous example will behaves the same with a
gamma expression.

(axi) println ((gamma (n) (+n 1)) 1)
2


     Selfreference
When combining a function expression with recursion, the
need for the function to call itself is becoming a problem
since that function expression does not have a name. For
this reason, the writing system provides the reserved
keyword selfthat is a reference to the function expression.
We illustrate this capability with the well‐known factorial
expression written in pure functional style.

(axi) println ((gamma (n)
    (if (<= n 1) 1 (* n (self (‐ n 1))))) 5)
120

The use of a gamma expression versus a lambda expression is
a matter of speed. Since the gamma expression does not have
free variables, the symbol resolution is not a concern here.

     Closedvariables
One of the writing system characteristic is the treatment of
free variables. A variable is said to be free if it is not
bound in the expression environment or its children at the
time of the symbol resolution. For example, the expression
((lambda (n) (+ n x)) 1)computes the sum of the argument
nwith the free variable x. The evaluation will succeeds if
xis defined in one of the parent environment. Actually this
example can also illustrates the difference between a lambda
expression and a gamma expression. Let’s consider the
following forms.

trans x 1
const do‐print nil {
  trans x 2
  println ((lambda (n) (+ n x)) 1)
}

The gamma expression do‐printwill produce 3since it sums the
argument nbound to 1, with the free variable xwhich is
defined in the calling environment as 2. Now if we rewrite
the previous example with a gamma expression the result will
be one, since the expression parent will be the top level
environment that defines xas 1.

trans x 1
const do‐print nil {
  trans x 2
  println ((gamma (n) (+ n x)) 1)
}









                            ‐69‐


With this example, it is easy to see that there is a need to
be able to determine a particular symbol value during the
expression construction. Doing so is called closing a
variable. Closing a variable is a mechanism that binds into
the expression a particular symbol with a value and such
symbol is called a closed variable, since its value is
closed under the current environment evaluation. For
example, the previous example can be rewritten to close the
symbol x.

trans x 1
const do‐print nil {
  trans x 2
  println ((gamma (n) (x) (+ n x)) 1)
}

Note that the list of closed variable immediately follow the
argument list. In this particular case, the function do‐
printwill print 3since xhas been closed with the value 2has
defined in the function do‐print.

     Dynamicbinding
Because there is a dynamic binding symbol resolution, it is
possible to have under some circumstances a free or closed
variable. This kind of situation can happen when a
particular symbol is defined under a condition.

lambda (n) {
  if (<= n 1) (trans x 1)
  println (+ n x)
}

With this example, the symbol xis a free variable if the
argument nis greater than 1. While this mechanism can be
powerful, extreme caution should be made when using such
feature.

     qualifiedLexicaland
The basic forms elements are the lexical and qualified
names. Lexical and qualified names are constructed by the
parser. Although the evaluation process make that lexical
object transparent, it is possible to manipulate them
directly.

(axi) const sym (protect lex)
(axi) println   (sym:repr)
Lexical

In this example, the protectreserved keyword is used to
avoid the evaluation of the lexical object named lex.
Therefore the symbol symrefers to a lexical object. Since a
lexical ‐‐ and a qualified ‐‐ object is a also a literal
object, the printlnreserved function will work and print the
object name. In fact, a literal object provides the to‐









                            ‐70‐


stringmethod that returns the string representation of a
literal object.

(axi) const sym (protect lex)
(axi) println   (sym:to‐string)
lex


     argumentSymboland
Each nameset maintains a table of symbols. A symbol is a
binding between a name and an object. Eventually, the symbol
carries the constflag. During the lexical evaluation
process, the lexical object tries to find an object in the
nameset hierarchy. Such object can be either a symbol or an
argument. Again, this process is transparent, but can be
controlled manually. Both lexical and qualified named object
have the mapmethod that returns the first object associated
in the nameset hierarchy.

(axi) const obj 0
(axi) const lex (protect obj)
(axi) const sym (lex:map)
(axi) println   (sym:repr)
Symbol

A symbol is also a literal object, so the to‐stringand to‐
literalmethods will return the symbol name. Symbol methods
are provided to access or modify the symbol values. It is
also possible to change the constsymbol flag with the set‐
constmethod.

(axi) println (sym:get‐const)
true
(axi) println (sym:get‐object)
0
(axi) sym:set‐object true
(axi) println (sym:get‐object)
true

A symbol name cannot be modified, since the name must be
synchronized with the nameset association. On the other
hand, a symbol can be explicitly constructed. As any object,
the =operator can be used to assign a symbol value. The
operator will behaves like the set‐objectmethod.

(axi) const sym (Symbol "symbol")
(axi) println sym
symbol
(axi) sym:= 0
(axi) println (eval sym)
0












                            ‐71‐


     Closure
As an object, the Closurecan be manipulated outside the
traditional declarative way. A closure is a special object
that holds an argument list, a set of closed variables and a
form to execute. The mechanic of a closure evaluation has
been described earlier. What we are interested here is the
ability to manipulate a closure as an object and eventually
modify it. Note that by default a closure is constructed as
a lambda expression. With a boolean argument set to true the
same result is obtained. With false, a gamma expression is
created.

(axi) const f (Closure)
(axi) println (closure‐p f)
true

This example creates an empty closure. The default closure
is equivalent to the trans f nil nil. The same can be
obtained with const f (Closure true). For a gamma
expression, the following forms are equivalent, const f
(Closure false)and const f nil nil. Remember that it is
transand constthat differentiate between a lambda and a
gamma expression. Once the closure object is defined, the
set‐formmethod can be used to bind a form.

# the simple way
trans f nil (println "hello world")
# the complex way
const f    (Closure)
f:set‐form (protect (println "hello world"))

There are numerous situations where it is desirable to mute
dynamically a closure expression. The simplest one is the
closure that mute itself based on some context. With the use
of self, a new form can be set to the one that is executed.
Another use is a mechanism call advice, where some new
computation are inserted prior the closure execution. Note
that appending to a closure can lead to some strange results
if the existing closure expression uses returnspecial forms.
In a multi‐threaded environment, the ability to change a
closure expression is particularly handy. For example a
special thread could be used to monitor some context. When a
particular situation develops, that threads might trigger
some closure expression changes. Note that changing a
closure expression does not affect the one that is executed.
If such change occurs during a recursive call, that change
is seen only at the next call.