%-*-mode:latex-*-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Copyright (C) 1996-2004 Jason Evans <jasone@canonware.com>.
% All rights reserved.
% 
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions
% are met:
% 1. Redistributions of source code must retain the above copyright
%    notice(s), this list of conditions and the following disclaimer
%    unmodified other than the allowable addition of one or more
%    copyright notices.
% 2. Redistributions in binary form must reproduce the above copyright
%    notice(s), this list of conditions and the following disclaimer in
%    the documentation and/or other materials provided with the
%    distribution.
% 
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
% EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
% PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
% OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
% EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Version: Onyx 5.1.1
%
% Onyx tutorial portion of Onyx Manual.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\clearemptydoublepage
\chapter{Onyx Language Tutorial}
\label{onyxtut}

This manual includes a comprehensive \htmlref{Onyx Language Reference}{onyxlang}
chapter, which explains the details of what Onyx is.  However, that chapter is
rather dry, and more importantly, it does not discuss how to best utilize Onyx.
This chapter introduces concepts that are important when designing and
implementing Onyx programs, though it is not a complete language tutorial.  You
will need to read the first several sections of Chapter~\ref{onyxlang} in order
to absorb all of the information in this chapter.  However, you should be able
to read this chapter first, then come back to it and glean additional
understanding after having read later chapters.

Onyx is a stack-based language, so although the ideas that are important to
program design in other more traditional languages still apply in many cases,
there are different ways of approaching certain problems that integrate better
with the facilities provided by Onyx.  The most obvious example of this is that
Onyx programs are more efficient if written to use named variables as little as
possible, relying instead on the power of the operand stack.  Another example is
error handling.  It is possible to write procedures that check for every error
condition, but Onyx provides a form of exception handling that, if used
correctly, can significantly improve code readability and performance.

Accomplished PostScript programmers will find little new in this chapter; Onyx
differs from PostScript in the details, but the concepts are very similar.
Accomplished Forth programmers will already be comfortable with stack
management, but the rest of the chapter discusses concepts that either have no
Forth equivalent, or that are significantly different from Forth, as is the case
for dictionaries.

\section{Syntax}

Onyx syntax is extremely simple.  Code is essentially composed of tokens that
are delimited by whitespace or a list of self-delimiting tokens (see
Section~\ref{sec:onyx_syntax} for details).  As such, there are very few ways
for a syntax error to occur, but typographical mistakes may instead produce
other errors.  For example, say that a C programmer forgets he is writing Onyx
code and types the following at the interactive \binname{onyx} prompt:

\begin{verbatim}
onyx:0> 1000L {`Hello\n' print} repeat
\end{verbatim}

The intention is to print {\tt Hello} 1000 times, but {\tt 1000L} is invalid
syntax for an integer, so Onyx creates an executable name object instead, and
then tries to execute the name, resulting in the following error:

\begin{verbatim}
Error $undefined
ostack: ()
dstack: (-dict- -dict- -dict- -dict-)
cstack: ()
estack/istack trace (0..2):
0:      1000L
1:      -file-
2:      --start--
\end{verbatim}

This is typical of the simple errors encountered when writing Onyx code.  The
Onyx scanner uses a simple state machine to try to create objects of various
types, and when it fails, the input is instead used to create an executable
name.

The scanner only deals with a few types (ignoring procedures for the moment):
integers, reals, names, and strings.  There are many other object types, but
none of them are created directly by the scanner.

\{ and \} are used to delimit procedure bodies, which in actuality are
executable arrays.  \{ puts the scanner into deferred execution mode until the
matching \} is scanned.  \{\} pairs can be nested, so execution is deferred
until matching \} characters have been scanned for all \{ characters.  Deferred
execution means that the scanner creates objects as it scans code, but does not
execute any of them.  While not a strictly necessary language feature, this
greatly simplifies the task of constructing executable arrays, which can then be
treated as procedures.

Following are equivalent examples of how a procedure associated with the name
{\tt double} can be defined:

\begin{verbatim}
onyx:0> $double {2 mul} def
onyx:0> $double [ 2 $mul load ] cvx def
\end{verbatim}

As mentioned earlier, there are few ways of generating a syntax error, but it is
possible.  The most common syntax errors are due to unmatched ' and \}
characters.  Generating other syntax errors is left as an exercise for the
reader.

\section{Data types}

Onyx includes a rich set of data types.  In fact, Onyx code is represented as
data, which means that there is a whole range of possibilities when writing Onyx
programs that are difficult or impossible with compiled languages such as C.
This aspect of Onyx is discussed in Section~\ref{onyxtut:introspection}.

Onyx is dynamically typed, which means that errors due to object type
incompatibilities are detected during program execution.  For example, the
following code will always run without an error, even though the arguments that
would be passed to the \htmlref{\onyxop{}{add}{}}{systemdict:add} operator are
invalid.

\begin{verbatim}
false {
    `a string' [1] add
}{
    `This is always printed' 1 sprint
} ifelse
\end{verbatim}

Dynamic typing has advantages in the flexibility that it offers, but it also
means that type errors can go undetected in code for long periods of time before
the invalid code is executed.

Onyx has a fixed set of basic types which cannot be extended.  However,
object-oriented programming is supported, so the fixed set of object types is
not a limitation in practice.  Object-oriented programming is discussed more in
Section~\ref{sec:onyx_oop}.

\section{Execution}

Onyx code is never compiled, nor is it preprocessed by the interpreter.  Onyx
code is simply consumed.  This has some interesting implications, some of which
are not typical of even other interpreted languages:

\begin{itemize}
\item{If a source file is modified during interpreter execution, the changes may
affect the currently running program, usually in unpleasant ways.}
\item{Syntax errors are not discovered until the malformed code is scanned.  In
order to be sure that there are no syntax errors, a source file must be
completely scanned.}
\end{itemize}

In practice, these are only minor inconveniences, but it is important to keep
them in mind when developing.

\section{Memory management}

Since Onyx includes an automatic mark and sweep garbage collector, memory
management typically requires little thought.  There is no risk of leaking
memory in such a way that it cannot be freed.  However, it is possible to
consume large amounts of memory by creating objects, then keeping references to
them long after they have outlived their usefulness.

Onyx objects fall into two categories according to type: simple and composite.
Simple objects take up no virtual memory of their own; they are embedded into
other composite objects.  For example, an integer on the operand stack takes up
only the space that the stack requires to store it.  The same is true of an
integer that is stored as an element of an array.  Composite objects are
composed of references that fit into the same places that an integer is stored,
plus additional structures stored elsewhere in virtual memory.  There can be
multiple references to the same composite object, and as there is a chain of
references that makes it possible to reach a composite object, the garbage
collector will leave it alone.

It is usually pretty obvious how to remove references to objects.  Objects on
the operand stack can be popped off.  Definitions in the dictionary stack can be
undefined.  However, there may be situations such an array that contains
references to various objects, and the array cannot be discarded as a whole, but
individual elements are no longer needed.  The null type is useful for
clobbering such references, and can even be effectively used to clobber portions
of procedures, since when a null object is executed it does absolutely nothing.
This unique aspect of null objects may not seem significant, but consider that
all other objects, when executed, are either pushed onto the execution stack and
executed, or pushed onto the operand stack.  Doing nothing at all can be useful.

\section{Stacks}

Stacks in Onyx are pretty typical, and a rich set of stack manipulation
operators is provided..  Objects are implicitly or explicitly pushed onto stacks
by operators, and the stack contents can be rearranged and removed.  Although
stacks are a first class object in Onyx, most Onyx programs are mainly concerned
with the operand stack, often referred to as ostack.  ostack is used as a place
to store objects, pass arguments into operators and procedures, and return
results.

Onyx is a postfix language, which means that code is written such that operands
precede operators.  For example, the following code Calculates $5 \times (3 +
4)$ and prints the result:

\begin{verbatim}
onyx:0> 5 3 4 add mul
onyx:1> 1 sprint
35
onyx:0>
\end{verbatim}

There are no parentheses to clarify operator precedence, because precedence is
implicit in the code.

Stacks are either written bottom to top on one line, or top to bottom on
separate lines, as in the following examples.  The example stack contains the
numbers 0, 1, and 2, where 0 is the top object and 2 is the bottom object:

\begin{verbatim}
onyx:0> 2 1 0
onyx:3> ostack 1 sprint
(2 1 0)
onyx:3> pstack
0
1
2
onyx:3>
\end{verbatim}

Learning to efficiently (and accurately) manage stacks is a mind-warping process
that no amount of reading is likely to impress upon the reader.  There are
general concepts presented here, but ultimately, the reader will have to write a
good bit of code to get a handle on stacks.  Tthe author of Onyx found himself
stumbling over stacks well after Onyx was complete, despite limited exposure to
stack-based languages beforehand.  The problem seems to be that programmers
learn to think in a different way that doesn't exercise the parts of the brain
necessary for stack manipulation.  Some people might argue that stack
manipulation is the job of the compiler.  In any case, stack manipulation is an
acquired skill that requires practice.

\subsection{Efficiency issues}

Stacks are implemented such that accessing an object is a constant-time
operation, regardless of its depth in a stack.  However, only the top and
bottom of a stack may be modified in constant time.

Typically, the cost of stack manipulations is proportional to the number of
objects being touched.  So, rolling the top ten objects is five times as costly
as exchanging the top two objects.  Likewise, rotating the stack by ten
positions is typically five times as expensive as rotating the stack by two
positions.  Costs for rolling and rotation are approximately proportional to
each other, though pathological cases for rotation incur a slightly higher
overhead (a constant factor more expensive, when amortized).

Stacks have more memory and performance overhead than arrays, so unless growing
or shrinking is imporant, arrays are a better choice for indexed access.
Dictionaries are always a better choice for keyed access.

\subsection{Using stacks as queues}

Since pushing and popping is efficient for both ends of stacks, this means that
stacks are suitable for use as queues.  Either orientation for input/output is
fine.

\subsection{Using the operand stack as two stacks}

The ability to efficiently manipulate both ends of the operand stack means that
the operand stack can effectively be thought of as two stacks.  This can be very
useful in situations where more than a handful of objects are being manipulated,
and an additional location to temporarily stash objects would be useful.  If a
program is repeatedly doing large stack rolls or rotations, using the bottom of
the stack can often help to simplify the code and reduce stack manipulation
overhead.

\section{Dictionaries}

Dictionaries are known by various other names, including hashes and associative
arrays.  Dictionaries in Onyx associate keys with values.  Keys and values can
be of any type, but for each dictionary, all keys are unique.  For example, the
following dictionary cannot exist:

\begin{verbatim}
<
    42 `Some value'
    42 `Another value'
>
\end{verbatim}

To demonstrate this, the following example creates a dictionary with the first
key/value pair listed above, then inserts the second key/value pair.

\begin{verbatim}
onyx:0> <42 `Some value'>
onyx:1> dup 1 sprint
<42 `Some value'>
onyx:1> dup 42 `Another value' put
onyx:1> dup 1 sprint
<42 `Another value'>
onyx:1>
\end{verbatim}

When the second key/value pair is inserted, it replaces the first pair.

Actually, there is one way to create a dictionary, then modify it such that
multiple entries have the same key.  However, doing so is a very bad idea, and
is only discussed here as an example of something {\em not} to do.  Dictionary
keys are merely references (in the case of composite objects), so if a string is
modified after being used as a dictionary key, the dictionary will no longer be
able to access the key/value pair associated with that string.  The following
code creates a dictionary with two key/value pairs, then changes one of the
keys.

\begin{verbatim}
onyx:0> $foostr `foo' def
onyx:0> $barstr `bar' def
onyx:0> $d <foostr 0 barstr 1> def
onyx:0> foostr barstr copy pop
onyx:0> d 1 sprint
<`foo' 1 `foo' 1>
onyx:0> d `foo' undef
onyx:0> d 1 sprint
<`foo' 0>
onyx:0>
\end{verbatim}

Bad things are clearly happening here, and in fact there are other similar
problems that surface, even if a key remains unique after being changed.  This
is because during insertion, the key string is hashed, and inserted into a hash
table accordingly.  A different string is likely to hash to a different slot in
the hash table, which means that the key/value pair becomes inaccessible.

In summary, do not change strings while they are being used as dictionary keys.
Onyx does not prevent the use of strings for dictionary keys, since it would be
limiting, but this feature can be abused.

\subsection{Efficiency issues}

Although dictionaries can handle keys of any type, they are optimized to use
names as keys.  The performance penalty for other key types is slight, but can
be exacerbated by the cost of comparison for other types.  Name comparison is a
constant time operation, but string comparison is not.  Therefore, use names
rather than strings whenever possible.

\section{Regular expressions}
Onyx provides regular expression support that is very similar to what the Perl
programming language provides.  There are two special data types, regex and
regsub, that are specific to regular expressions, but there is no special
language syntax devoted to regular expressions, unlike Perl.  Instead, patterns
and substitution templates are specified via normal strings, and flags are
specified via dictionaries.

Regular expression syntax is similar to that of Perl.  See
Section~\ref{sec:onyx_regular_expressions} for more information.

\subsection{Matching}
The following snippet iteratively searches for capitalized words:

\begin{verbatim}
`This is an Onyx string.'

{dup `[A-Z]\w+' <$g true> match}{
    0 submatch 1 sprint
} while
\end{verbatim}

The above code generates the following output:

\begin{verbatim}
`This'
`Onyx'
\end{verbatim}

The {\tt \$g} flag to the \htmlref{\onyxop{}{match}{}}{systemdict:match}
operator says to start searching where the previous match ended, which is what
makes the {\tt while} loop possible.  The
\htmlref{\onyxop{}{submatch}{}}{systemdict:submatch} operator gets the substring
of the input string that the regular expression most recently matched.

With a slight modification to the previous example, it is possible to get at the
capital letters, rather than the entire capitalized words.  This is achieved by
using a set of capturing parentheses, and changing the argument to
\htmlref{\onyxop{}{submatch}{}}{systemdict:submatch}:

\begin{verbatim}
`This is an Onyx string.'

{dup `([A-Z])\w+' <$g true> match}{
    1 submatch 1 sprint
} while
\end{verbatim}

This generates the following output:

\begin{verbatim}
`T'
`O'
\end{verbatim}

This is a trivial example of how capturing subpatterns can be used, but the
possibilities are wide and varied.

\subsection{Splitting}

Sometimes it is desirable to \htmlref{\onyxop{}{split}{}}{systemdict:split} a
string into pieces, such as when dealing with a comma-delimited file:

\begin{verbatim}
`Jason Evans, jasone@canonware.com, http://www.canonware.com/~jasone/'

`,\s*' split
1 sprint
\end{verbatim}

This generates the following output:

\begin{verbatim}
[`Jason Evans' `jasone@canonware.com' `http://www.canonware.com/~jasone/']
\end{verbatim}

If for some reason preserving the delimiters is important, capturing parentheses
can be added to the splitting pattern:

\begin{verbatim}
`Jason Evans, jasone@canonware.com, http://www.canonware.com/~jasone/'

`(,)\s*' split
1 sprint
\end{verbatim}

This generates the following output:

\begin{verbatim}
[`Jason Evans' `,' `jasone@canonware.com' `,' `http://www.canonware.com/~jasone/']
\end{verbatim}

\subsection{Substituting}

The \htmlref{\onyxop{}{match}{}}{systemdict:match} and
\htmlref{\onyxop{}{split}{}}{systemdict:split} operators provide enough power
that with some effort, it is possible to find regular expression matches, modify
the matched text, and create a modified string as output.  However, this is a
common operation when using regular expressions for text processing, so the
\htmlref{\onyxop{}{subst}{}}{systemdict:subst} operator is also provided as a
more convenient interface for the most common types of substitution.

Suppose that a list of email addresses needs to be converted from one format to
another..  The following snippet does such a conversion:

\begin{verbatim}
`Jason Evans (jasone@canonware.com)
Jason O. Evans ( jasone@canonware.com )
'

`(\w[A-Za-z. ]*\w) \(\s*([^\s]+)\s*\)' `"\1" <\2>' <$g true> subst pop
stdout exch write pop
\end{verbatim}

This generates the following output:

\begin{verbatim}
"Jason Evans" <jasone@canonware.com>
"Jason O. Evans" <jasone@canonware.com>
\end{verbatim}

\section{Code organization}

As mentioned earlier, Onyx does not have named variables in the same way as most
other languages do.  However, it does have the dictionary stack (dstack), which
is dynamically used for name lookups whenever an executable name is interpreted.
This section talks about how to effectively manage the namespace provided by
dstack.

When the Onyx interpreter is first initialized, there are four dictionaries on
dstack:

\begin{itemize}
\item{userdict}
\item{globaldict}
\item{systemdict}
\item{threaddict}
\end{itemize}

dstack can be manipulated any way the application sees fit, though it is
generally dangerous to remove or significantly modify systemdict or threaddict,
since there are definitions in those dictionaries that are critical to the
correct functioning of the interpreter.

Each thread has its own userdict, which provides a thread-local namespace.
globaldict is shared among all threads, so it provides a global namespace.
systemdict contains all of the default global definitions, and threaddict
contains the default thread-local definitions.

For some applications, it may be desirable to add definitions to systemdict, but
care should be taken not to overwrite existing definitions unless you really
know what you are doing.  In most cases, using globaldict is a better way to
go.

\subsection{Procedures}

Named procedures can be created by associating a name with a procedure in one of
the dictionaries on dstack.  There is nothing magical about this, but some care
should be taken in choosing procedure names, and in deciding how to manage the
namespace.  Onyx uses only numberss and lowercase letters in the names of its
definitions on dstack, so it is easy to avoid namespace collisions by using some
other character in program definitions.  There is nothing wrong with using all
numbers and lowercase letters for names in your programs, though some extra care
is warranted when doing so.

An important consideration in program design is determining what belongs in the
global namespace.  For an example of how Onyx partitions its namespace, look at
gcdict.  There are several operators defined in gcdict that are only of interest
when manipulating the garbage collector, so those definitions are stashed out of
the way.  Your program can do the same for definitions that are not of regular
interest.

%%\subsection{Object-oriented programming}
%%\label{onyxtut:object_oriented_programming}

\subsection{Modules}
Onyx provides the infrastructure for loadable modules, which can be implemented
as Onyx code and/or dynamically loaded machine code (shared libraries).  At the
lowest level, \htmlref{\onyxop{}{modload}{}}{systemdict:modload} can be used to
load a shared object.  At a higher level,
\htmlref{\onyxop{}{mrequire}{}}{systemdict:mrequire} can be used to find a
shared object in one of the directories specified by the module path, then
\onyxop{}{modload}{} it.  At the highest level, the \classname{mclass} and
\classname{module} classes provide methods for loading, introspecting, and
unloading modules.  The lower level APIs are typically only utilized when
writing modules, and the highest level APIs are utilized when using modules.

When writing a module that is meant as a library of additional functionality,
some choices have to be made about how to organize the module.  Some of the
obvious choices for how to organize the loaded definitions are:

\begin{itemize}
\item{Insert definitions into globaldict.}
\item{Create a new dictionary full of definitions, and insert the dictionary
  into globaldict as, say, foodict.}
\item{Insert definitions into systemdict (questionable practice).}
\end{itemize}

Depending on the nature of the module, any of the above solutions may be the
right choice.  There are tradeoffs between convenience and cleanliness that
should be carefully weighed.

\section{Error handling}
Onyx includes a powerful generic error handling mechanism that can be extended
and customized at several levels.  The
\htmlref{\onyxop{}{throw}{}}{systemdict:throw} procedure is used to throw an
error, and virtually every aspect of the error handling machinery can be
customized, extended, or replaced, since it is all written in Onyx.

Errors have names, with which error handlers can be associated in errordict.
errordict's \htmlref{\onyxop{}{handleerror}{}}{errordict:handleerror} procedure
can be modified or replaced.  In fact, with some care, an entirely custom
errordict can be defined, then undefined once it is no longer needed.

Following is the standard idiom for setting up and tearing down custom error
handling:

\begin{verbatim}
# Set up custom error handling...
{
    # Do error-prone stuff...
} stopped {
    # An error occurred.  Do additional cleanup...
} if
# Restore error handling machinery...
\end{verbatim}

The possibilities are extensive.  However, a few words of caution are in order.
If you mess something up in the error handling machinery, bad things will
happen, and you will have a terrible time debugging the problem.  Be careful.

\section{Introspection}
\label{onyxtut:introspection}

The following code defines a named procedure that calculates factorials:

\begin{verbatim}
#n factorial #result
$factorial {
    dup 1 gt {
        #n-1 factorial
        dup 1 sub factorial
    }{
        # Terminate recursion.
        1
    } ifelse

    mul
} def
\end{verbatim}

What this code actually does is create an executable array, which can be
examined and modified.  The following transcript shows the effects of modifying
the code:

\begin{verbatim}
onyx:0> 3 factorial 1 sprint
6
onyx:0> $factorial load 2 sprint
{dup 1 gt {dup 1 sub factorial} {1} ifelse mul}
onyx:0> $factorial load 4 {1 pstack} put
onyx:0> 3 factorial
1
1
2
3
onyx:1> 1 sprint
6
onyx:0>
\end{verbatim}

First $3!$ is calculated.  Then the ``else'' clause of the ifelse construct is
modified to print the stack and $3!$ is recalculated.  As can be seen, the stack
is printed during the calculation.

\section{Threads}

The original impetus for Onyx's creation was the need for scalable threading.
Onyx's threading is therefore truly powerful, though it comes at a cost.
Threading makes asynchronous garbage collection a necessity, which in turn makes
many aspects of Onyx's implementation a bit more heavyweight than would be
necessary for a single-threaded interpreter.

\subsection{Implicit synchronization}

Onyx provides mechanisms for implicit object synchronization.  To see why
implicit object synchronization is necessary, consider what happens when two
threads concurrently modify globaldict (a perfectly legitimate thing to do, by
the way).  The internals of a dictionary are rather complex, and if two
modifications were interleaved, havoc would ensue.  Therefore, globaldict is
implicitly locked.  That is a good thing, except that it slows down every access
to globaldict.  In contrast, userdict is a per-thread dictionary, so it is not
implicitly locked.

Implicit locking for new objects is controlled via
\htmlref{\onyxop{}{setlocking}{}}{systemdict:setlocking}, and can be queried via
\htmlref{\onyxop{}{currentlocking}{}}{systemdict:currentlocking}.  Implicit
locking is turned off by default when Onyx is started up, so if an application
needs to create an object that is shared among threads, it should temporarily
turn on implicit locking.  For example, the following code creates a stack in
globaldict that can be used as a simple message queue:

\begin{verbatim}
currentlocking # Save for later restoration.
true setlocking

# Push globaldict onto dstack before calling def.
globaldict begin
$queue stack def
end # globaldict

# Restore implicit locking mode.
setlocking
\end{verbatim}

For additional details on the mechanics of implicit synchronization, see
Section~\ref{sec:onyx_implicit_synchronization}.

\subsection{General threading concerns}

Onyx's basic threading mechanisms are typical of those found in modern threading
implementations.  One of the aspects of Onyx's threading implementation to be
aware of is that since the operating system's threading implementation is used,
there are many types of programming errors that can cause undefined behavior.
With some effort, it is possible to crash the Onyx interpreter without the use
of threads.  However, it requires skill and discipline to {\em not} crash the
Onyx interpreter when using threads.  This was a conscious design decision for
Onyx; doing otherwise would have limited the scalability of threading.

\section{Optimization}

There are many fine points to optimizing Onyx code, but they can primarily be
distilled down to the following simple rules:

\begin{itemize}
\item{Avoid allocating composite objects, in order to reduce pressure on the
  garbage collector.  This means being very careful about string manipulation in
  the fast path.  The \htmlref{\onyxop{}{cat}{}}{systemdict:cat} operator is
  convenient, but not friendly to the garbage collector.}
\item{Write code with as few objects as possible, to reduce the number of times
  through the interpreter loop.  This means getting very familiar with the stack
  manipulation operators.}
\item{Use the operand stack rather than named variables.}
\item{Use the \htmlref{\onyxop{}{bind}{}}{systemdict:bind} operator for
  procedure definitions whenever possible, in order to reduce dstack lookups.}
\item{Avoid the \htmlref{\onyxop{}{exit}{}}{systemdict:exit},
  \htmlref{\onyxop{}{stop}{}}{systemdict:stop},
  \htmlref{\onyxop{}{escape}{}}{systemdict:escape}, and
  \htmlref{\onyxop{}{quit}{}}{systemdict:quit} operators when possible, since
  they are implemented via \cfunc{longjmp}{}.}
\end{itemize}

\section{Debugging}

Onyx does not have an integrated interactive debugger per se, because the
introspective power of Onyx is adequate for almost all debugging purposes.  In
cases where it is impractical to interactively debug an application via the main
thread, it is possible to launch a thread that listens for connections on a
socket (or a fifo pair) and provides an interactive session.

Following is a contrived example of debugging some bad code, interleaved with
explanations.  The intention is to calculate $1 + 5$.

\begin{verbatim}
onyx:0> 1 5L add
Error $undefined
ostack: (1)
dstack: (-dict- -dict- -dict- -dict-)
cstack: ()
estack/istack trace (0..2):
0:      5L
1:      -file-
2:      --start--
onyx:2> pstack
5L
1
\end{verbatim}

{\tt 5L} is not a number, nor is it defined in dstack.  Try replacing {\tt 5L}
with {\tt \$five}.

\begin{verbatim}
onyx:2> pop $five resume
Error $typecheck
ostack: (1 $five)
dstack: (-dict- -dict- -dict- -dict-)
cstack: ()
estack/istack trace (0..2):
0:      --add--
1:      -file-
2:      --start--
onyx:3> pstack
--add--
$five
1
\end{verbatim}

{\tt \$five} is a literal name, so no errors occur directly due to scanning it.
However, the \htmlref{\onyxop{}{add}{}}{systemdict:add} operator expects two
numbers, and {\tt \$five} is not a number.  Replace it with {\tt 5} and evaluate
the operator.

\begin{verbatim}
onyx:3> nip 5 exch eval
onyx:1> pstack
6
\end{verbatim}

The result is as desired.  However, we forgot to
\htmlref{\onyxop{}{resume}{}}{onyx_interactive:resume} after the last error.

\begin{verbatim}
onyx:1> estack 1 sprint
(--start-- -file- --add-- --ifelse-- --eval-- -array- -file- --estack--)
onyx:1> resume
\end{verbatim}

Now the estack contents should be back to normal.

\begin{verbatim}
onyx:1> estack 1 sprint
(--start-- -file- --estack--)
onyx:1>
\end{verbatim}

The above example only demonstrates the flavor of typical interactive debugging,
but there is no magic involved in debugging, so your debugging ability should
improve automatically as you gain an improved understanding of Onyx.