Additions to Logo Library
*************************

There is no difference between these procedures and other procedures
in Logo library. They are coded in standard Logo, and are
automatically copied to logolib directory during installation of
LOGO-MODE on UN*X machines. On other OSs, you will have to do this
manually. They are loaded ON DEMAND, just like the rest of Logo
library. Most of them are included, because they are needed by LOOPS
code, or were useful during development testing and profiling LOOPS
(like `time' procedure). Some will not be portable like (`time'
again), but all are useful in their own right.

before
------

     (before word)
     before word1 word2
     (before word1 word2 ...)

operation. Outputs (alphabetically) smallest word from input words.
Uses beforep for comparison.

max
---

     (max number)
     max number1 number2
     (max number1 number2 ...)

operation. Outputs numerically largest number from input numbers.
Uses greaterp internally.

min
---

     (min number)
     min number1 number2
     (min number1 number2 ...)

operation. Outputs numerically smallest number from input numbers.
Uses lessp internally.

evenp
-----

     evenp number
     even? number

outputs TRUE if the input is an even number, FALSE otherwise.

oddp
----

     oddp number
     odd? number

outputs TRUE if the input is an odd number, FALSE otherwise.

zerop
-----

     zerop number
     zero? number

outputs TRUE if the input is equal to 0, FALSE otherwise.

identity
--------

     identity stuff

outputs its argument. It is normally used as a first input to Higher
order Logo Procedures:

     to list.copy :lst
     op map "identity :lst
     end

last.pair
---------

     last.pair list

outputs last pair of a list. (as in last CONS CELL, or last node). It
will work with words, but makes no sense there--using last is faster.
Normally used for creation of circular structures:

     make "lst [1 2 3 4 5]
     show :lst                   => [1 2 3 4 5]
     .setbf last.pair :lst :lst
     show :lst                   => [1 2 3 4 5 1 2 3 4 5 1 2 3 ...]

split.word
----------

     (split.word word)
     split.word word delimiter

outputs a list, consisting of parts of the input WORD split on the
delimiter (with delimiter removed). When applied to one input only (a
word) delimiter is space by default.

     show split.word "circular.list.class ".   => [circular list class]

time
----

     time instructionlist

operation or command, depending on wether INSTRUCTIONLIST outputs or
not. Runs the INSTRUCTIONLIST, possibly outputs the result of
INSTRUCTIONLIST, and then prints the total time used. Resolution is
poor--second only, so set up longer tests for accurate measurements.
Works only on UN*X.

     time [quick.sort map "random iseq 1 1000]
     [0 0 0 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2 2 2 2 3 3 3 3 ...]
     Elapsed time: 15 seconds

begin
-----

     begin list.of.instructionlists

operation. A control structure that runs all INSTRUCTIONLISTS, and
outputs the result of the last one. Can be defined as:

     run apply "se :list.of.instructionlists

Only the last INSTRUCTIONLIST can output, or `begin' will not reach
it. It appears to be similar to `.and' control structure, but there
are some important differences; `.and' will exit on first input that
returns "FALSE--`begin' can not be used with inputs that return
anything (except the last one). `.and' can not handle inputs with
side effects--`begin' can.  See dAND.

Object Oriented Programming
***************************

LOOPS is a rudimentary Logo Object Oriented Programming System. It is
really too small, and slow, for serious practical use, but--with Logo
being what it is, language for learning and exploration, LOOPS fits
that context nicely. If you want to try developing your own set of
classes in Logo, this is a good start.

Introduction
============

The core ideas of object oriented programming differ considerably
from the ideas that were used to develop Logo. At a minimum, we
should be able to create objects as black boxes. That is--objects
will have their private persistent storage, and their own methods
(functions) to operate on that storage.

Logo provides neither. It does have private storage (local
variables), but they are not persistent. As soon as the object has
completed its immediate task, its local storage is freed. On the next
invocation of the same object, local storage is reinitialized, and
thus its previous state forgotten.

To clarify this, consider that we want to create a counter object.
The counter's storage is initialized to 0 on creation of object. We
want to be able to send the counter messages `increment', and
`decrement'. We could try to do this in Logo by defining procedure
`counter':

     to counter :message
     localmake "storage 0
     if equalp :message "increment [make "storage :storage+1 op :storage]
     if equalp :message "decrement [make "storage :storage-1 op :storage]
     op (se "counter "does "not "understand :message)
     end

No matter how many times we send counter object message `increment',
it will always output 1, likewise if the message is `decrement', it
will always output -1. This is obviously not what we want.

We could use a global variable STORAGE, and initialize it only once.
This would work, but it would also violate the principle of object as
a black box. Its private storage has now moved to global name-space,
and all other procedures can access it and tamper with it. To further
aggravate the problem, if we wanted a second counter, we would have
to create the second global storage (with a different name), and so
on.

This also means that second object can not use the same procedure as
the first one, because the name of the storage has changed. Not being
able to use the same procedure as a template for creating all objects
of the same type, means that we cannot create counter class, and
classes are the foundation of OOP.

We still haven't mentioned the second problem--private methods. Logo
does not have local procedures, therefore objects can not have them
either. Fortunately, the solution for this problem is obvious. See
LOCAL PROCEDURES.

We can use `letrec' to create object methods--but let's not get ahead
of ourselves. We still need to solve the persistent (static) storage
problem.

Static storage obviously must be some sort of global storage. The
problem is twofold; how to hide it to make it inaccessible to other
objects, and how to handle different names, so that the same
procedure (class) can be used as a template for creation of all of
its instances (objects).

I have chosen Logo property lists for static storage. Handling of
different names is done automatically by the `object.maker', class to
object transformer (compiler) procedure. Just how this is done will
be explained later. See IMPLEMENTATION.

This is all completely transparent for the LOOPS user/programmer, and
the full understanding of how `object.maker' works is not important.
It is however important to understand the following principles:

LOOPS objects are procedures. Some of them are real Logo procedures
(top level objects, but most will be virtual procedures (just like
procedures in `letrec'). Programmer programs them by writing a
template procedure (class); `object.maker' is then applied to the
class procedure (with possible initializing inputs), to actually
create an object. After that object can be used (run) by sending it
messages, to which it knows how to respond.

Class (template) procedures have the following syntax:

     to classname.class [input ...]
     [compile-time code used to set up the environment for static line]
     ...
     [static [...]]
     ...
     lambda :message
     run-time code that will form object procedure
     ...
     end

That would be:

     zero or more INPUTs to initialize the object's static storage

     zero or more lines of code that will run during compile--time

     zero or more lines starting with word `static'

     one `lambda :message' line

     one or more lines of Logo code that will actually form the object procedure

Note that square brackets mean optional (zero or more), and are not
part of the class syntax.

The class procedure name *must* end with `.class'. `object.maker'
does not care about that, and will accept class template of any name,
but the extension must be there anyway, to protect class procedures
from accidental compilation. If you use logo-mode command COMPILE
WORKSPACE, this will first filter out all procedures that have
`.class' extension, and then compile the rest. Compiling a class,
firstly--makes no sense, and secondly--will break the `object.maker'.

Lambda line is mandatory. It simply marks the divide between compile
time part of the object (top), and runtime part (bottom). The
variable `:message', does not have to be called that (it just makes
sense to do so). You can call it anything, as long as you are
consistent.

The compile time part of the class (lines above the `lambda' line)
will not show in object itself, at least not in that form. They serve
the purpose of allocating and initializing the object's static
storage, checking the validity of optional inputs, and whatever else
is needed to set up the compile-time environment for `static' line.
The runtime part of the class (lines below `lambda' line will form
the body of object procedure as they are, or compiled by
loops.compiler if they contain `case', `cond', or `letrec'
structures. Compilation is automatic, started by `object.maker'. It
cannot be run manually, as each object creates (zero or more)
sub-objects from which it inherits some of its methods. As these
objects are virtual procedures, loops.compiler (run manually from
top-level) would not be able to compile them.

Objects are defined this way:

     define "objectname (object.maker "classname.class [input ...])

This will create object (global procedure) OBJECTNAME, and initialize
its static storage with INPUT. Input is optional.

To use the object, send it messages:
     send "objectname "message
     (send "objectname "message1 "message2 ...)

It would be easier to use a direct way to invoke objects:
     objectname "message
but I chose to use the `send' procedure instead. There are two
advantages to using `send'. It let's me pass the name of the object
(to the object) consistently, in case  object needs to call itself,
and lets me dereference object's name several levels deep, therefore
ensuring uniform syntax for calling objects; object name is ALWAYS
quoted. Otherwise, in certain situations the programmer would have to
dereference the name manually by using `:' instead of `"'.

I am aware that this sounds a bit vague now, but it will be easier to
understand when we discuss base classes. See BASE CLASSES.

OOP Auxiliary Procedures
========================

Before we can start writing classes, we need a small set of auxiliary
procedures, that make LOOPS work.

object.maker
------------

     (object.maker classname optional.arguments)

operation. Outputs the text (in the format that Logo procedure `text'
outputs) of the newly created and compiled object. Takes one
mandatory input--CLASSNAME, and zero or more optional arguments,
normally initializing values for object's static storage. How
many--if any, depends on the class itself, as it is the class that
needs optional inputs.

send
----

     send objectname message
     (send objectname message1 message2 ...)

operation. Sends object OBJECTNAME the message MESSAGE, and outputs
the result returned by the object. The main task of `send' is to
completely dereference the OBJECTNAME, and send to the object either
the real global *name* of the object (if object is a global
procedure), or the actual *object itself*, if object is a virtual
procedure.

indirect
--------

     indirect idirect.objectname message
     (indirect indirect.objectname message1 message2 ...)

operation. Used for indirectly addressing objects, instead of:
     send send indirect.objectname "indirect message
Outputs whatever indirectly addressed object outputs, as a response
to the MESSAGE.See DIGITAL CLOCK.

delegate
--------

     delegate objectname messagelist

operation. Takes two inputs, OBJECTNAME, and MESSAGELIST, and invokes
the object on the `messagelist'. As the name suggest, it delegates
(passes on part of the objects job, to the classes (objects) whose
storage and methods `objectname' inherits.

static.make
-----------

     static.make varname val

command. Works like Logo `make'. Sets the value of VARNAME to the
value VAL, but also changes the value of the property VARNAME to the
value VAL. To fully understand the functioning of static storage, and
bucket.class, one must understand the implementation of `static.make':

     .macro static.make :name :value
     pprop :#in.procedure# :name :value
     output (list "apply ""make (list :name :value))
     end

This code should be examined after reading `bucket.class'
implementation BUCKET.

This procedure is actually redundant. It was the part of the first
implementation of LOOPS, and is left here (just as the bucket.class
is), because it is easy to implement, and understand--for beginner
LOOPS programmers to play with. The current implementation of LOOPS
uses pointers instead of `ctatic.make'.

method.export
-------------

     method.export classlist methodtext

operation, with side-effects. Takes two inputs, a list of classes, to
which method is to be exported, and the METHODTEXT (list of lists).
Outputs the compiled version of the METHODTEXT.

Base Classes
============

This is a minimum set of classes that were needed to test the system.
Some were chosen more on the merit of being a challenge to develop,
than of real usefulness to everyday programming.

All objects created (defined) by these classes are black boxes that
receive messages and act upon them. Just what messages are understood
by each object will be listed later. There is one message common to
all objects, and that is TYPE. All objects will respond to that
message by returning their *class* type.

If you have defined the object `counter1', based on
REWINDING.COUNTER.CLASS, the `counter1''s response to message
`send "counter1 "type' will be REWINDING.COUNTER.OBJECT, and not
COUNTER1.OBJECT.

The other important fact to remember about a class is; although all
classes are valid Logo procedures, they are NOT meant to be executed
directly. Their purpose is to serve only as a blueprint (template),
based on which `object.maker' creates an instance of a class--object
that can be executed directly. To prevent possible confusion as a
result of user trying to run the class procedure directly, `lambda'
is defined as a procedure that throws TOP-LEVEL with an error message.

base object
-----------

`base.object' is the one exception here. Technically it is not a
class at all, but a straight forward object (globally defined
procedure).

There are two good reasons for defining `base.object' this way. Every
other object (class) needs the `base.object' as the last object in
the delegation (inheritance) chain, which means, that the number of
`base.object's defined in the end would be large. That's OK if there
was a real need for so many--or even two separate `base.objects', but
there is not. `base.object' is the only object (class) that I have
defined in LOOPS that does not have its own static storage. Simply
put--there is no need for more than one. However note; the
`base.object' *must* be included in *all* classes that you define
either explicitly; as in `delegate "base.object :message', or
implicitly by delegating to another class that (somewhere down the
chain of delegation) has explicit delegation to `base.object'.

The reasons for this rule will became obvious, after the explanation
of messages that `base.object' responds to.

`error'
     This is user generated error (user requested error) in some
     other class that was delegated to the `base.object', which then
     displays the message that was sent with it, and throws
     top-level. That is necessary, because Logo does not have Scheme
     like ERROR procedure--so instead of printing error message and
     throwing top-level everywhere you need this, you simply send the
     word "error with the error message text to the `base.object'.

`erase.object'
     `base.object' is the only object that possesses the method for
     deleting any top-level object, its sub-objects, and all of their
     static storage. *This is very important*. Logo automatic memory
     management does not work with LOOPS. Garbage collector will not
     know which virtual objects (values in property lists) to trash
     if you delete manually (with `erase') only the top-level object.
     As objects take up a lot of space (far more than standard Logo
     procedures), it is important to send the top-level object
     message ERASE.OBJECT, when it is no longer needed.

`anything-not-caught-by-higher-level-objects'
     This is a catch-all error message. Any message (probably
     misspelled) sent to any of the objects higher in the delegation
     chain will filter down to the `base.object', which will then
     display the message:
     MESSAGE NOT UNDERSTOOD BY OBJECT: OBJECTNAME, and throw
     top-level.

bucket class
------------

This class was designed as the only access to any object's static
storage. However, now is redundant, and is included here only because
it is simple to understand, implement, and explain. It is still
available in LOOPS, so anybody wishing to use it, can do so.

     to bucket.class :init
     static [[contents :init]]
     lambda :msg
     local "message make "message first bf :msg
     if.tf equalp :message "get [op :contents]
     if.tf equalp :message "indirect [op :contents]
     if.tf equalp :message "set ~
           [static.make "contents last :msg op :contents]
     if.tf equalp :message "type [op "bucket.object]
     op delegate "base.object :msg
     end

Probably the best way to understand this `static storage' business,
is to create one instance of the BUCKET.CLASS, and inspect its code:

     define "bucket1 (object.maker "bucket.class 0)

     show fulltext "bucket1

     to bucket1 :msg
     local [#in.procedure# contents]
     make "contents gprop "g1.g2.bucket.class "contents
     make "#in.procedure# "g1.g2.bucket.class
     local "message make "message first bf :msg
     if.tf equalp :message "get [op :contents]
     if.tf equalp :message "indirect [op :contents]
     if.tf equalp :message "set ~
           [static.make "contents last :msg op :contents]
     if.tf equalp :message "type [op "bucket.object]
     op delegate "base.object :msg
     end

The output of `fulltext' was hand-formated to make it easier to read.

Let's first deal with the part of the `bucket.class' below LAMBDA
line. If you compare class code and object code, you will see that
they are identical. `object.maker' simply copied all lines below
LAMBDA to the object. That is why this part is called the run-time
part of the class. I take it--no further explanation is necessary
here.

The top part consisting only of the line `static [[contents :init]]'
is more interesting, and is responsible for the top three lines in
the object. This part (above LAMBDA line) is called; the compile-time
part of the class.

The format of `static' line is following:

     static [[static-variablename1 value-expression1]
             [static-variablename2 value-expression2]
              ...
            ]
     static [[static-variablename3 value-expression3] ...]

Anybody familiar with Lisp will realize that this is just a copy of
the Lisp LET form. The second STATIC line is equivalent to nested LET
lines. Why do we need more than one STATIC line? To resolve the scope
problem. All VARIABLENAME--VALUE-EXPRESSION pairs in one STATIC line
are executed in parallel, which means that VALUE-EXPRESSION2 can not
use the value of STATIC-VARIABLENAME1, because--technically speaking,
at the moment when VALUE-EXPRESSION2 needs this value, it does not
yet exist. However, the second STATIC line can use values of both
STATIC-VARIABLENAME1, and STATIC-VARIABLENAME2.

When `object.maker' finds the word STATIC in the text of a class it
will convert the list after it to the top three lines in the `bucket'
object, and prepend it to the runtime part of the class. The
important issue to understand here is that although `object.maker' is
an operation (outputs the code of the object), it is an operation
with side-effects. Before it outputs the text, it will carry out the
following assignment (command):

     pprop "g1.g2.bucket.class "contents 0

This 0, is the initializing value passed to the `object.maker' as a
second input. It is, perhaps, easier now to understand the line
`make "contents gprop "g1.g2.bucket.class "contents' in the `bucket1'
object.

During compile-time, static storage--property list with the name
"g1.g2.bucket.class was created. Its property "contents was set to 0.

During run-time, when the object `bucket1' is executed, first thing
it must do, is to retrieve this property, and make it conveniently
available as a local variable with the same name; CONTENTS.

After that `bucket1' can use it as if it were an ordinary local
variable. There is one important exception. If `bucket1' needs to
(permanently) change the value of CONTENTS it must use `static.make'.
Logo `make' would only change the value of the local variable
CONTENTS, which is not enough if we want the change to persist until
the next invocation of `bucket1'.

That's why we need the second variable with the name #IN.PROCEDURE#.
This variable is created for every BUCKET.CLASS object, and is used
by `static.make'. See STATICdMAKE.

It should be obvious that the name #IN.PROCEDURE# is best avoided in
any of the classes you define, as this could result in the name clash.

Bucket class responds to the following messages:

`get ; indirect'
     Outputs the value of the variable CONTENTS (in our case 0).

`set VALUE'
     Changes the value of the (static) variable CONTENTS to VALUE,
     and outputs that value.

After having read and understood all of this--you can safely forget
the `bucket.class', and concentrate on the next one (`pair.class'),
as this is the only static storage access class used in the rest of
the LOOPS code.

pair class
----------

As mentioned before, this should be the *only* class used to acces
static storage. Its implementation is superior to bucket.class (which
it replaces) for two reasons; It does not have to use hand written
kludge (like procedure `static.make') to change static storage.
Insted, it uses Logo primitives `.setfirst', and `.setbf'. This makes
the code faster and cleaner. The added benefit is that the
`pair.class' can store two independent values instead of only one.

Unlike `bucket.class', the `pair.class' accesses static storage via
the header--a cons cell, commonly called `dotted pair' or `improper
list'. The storage is changed by directly manipulating pointers to
dotted pair's first and butfirst parts. If this `dotted pair' has
caused confusion--well, it is a standard Lisp structure that
apparently exists in Logo as well (although it is not documented). It
consists of one cons cell (node) that holds pointers to first and
butfirst parts. The only difference between dotted pair, and ordinary
list is that butfirst pointer of the proper list must point either to
the rest of the (proper) list (if the list has more than one
element), or to the empty list. The butfirst pointer of a dotted pair
can point to an atomic structure (no empty list at the end).

The `pair.class' header cell, does not always have to be dotted pair,
it can also be a proper list. If the the class instance (object) was
created with only one initializing value, then it will be a proper
list. You will understand this better after examining the class code:

     to pair.class :xinit [:yinit []]
     local "cons.cell
     make "cons.cell (list :xinit) .setbf :cons.cell :yinit
     static [[pair.o :cons.cell]]
     lambda :msg
     op case [
        [first bf :msg]
        [[get getx indirect] [first :pair.o]]
        [[set setx] [.setfirst :pair.o last :msg first :pair.o]]
        [[gety] [bf :pair.o]]
        [[sety] [.setbf :pair.o last :msg bf :pair.o]]
        [[raw] [:pair.o]]
        [[p2l] [list first :pair.o bf :pair.o]]
        [[type] ["dotted.pair.object]]
        [else [delegate "base.object :msg]]]
     end

First we have to explain the purpose of the first two lines. These
lines belong to the compile-time part of the class, but they differ
substantially from the STATIC line. Static line will run during
compile-time of the class, but will also leave the result in a
run-time part of the object. Lines before `static' line will run
during compile-time, but will not output to the run-time part of the
object. They are here simply to set up the environment for the STATIC
line. That's why all of them *must* come before the first STATIC line.

In the case of `pair.class', first two lines will create the dotted
pair structure. It is easier to understand now, that--if YINIT is not
given; it will default to the empty list, thus making the CONS.CELL
into a proper list.

When it comes to the number of inputs an LOOPS class can handle; they
are just like ordinary Logo procedures. They take required inputs
(:XINIT), optional inputs ([:YINIT []], and rest inputs (pair.class
does not have those). The input syntax is the same as the standard
Logo syntax, with the exception that the default number of inputs is
not needed. It is not an error to append a number specifying that,
but do not waste your time--`object.maker' will simply strip it from
the class text. Class is never applied to its inputs,
instead--`object.maker' is applied to both, the class and its inputs.
As the call *must* be enclosed in parenthesis, there is never any
ambiguity, about their number.

The run-time part of the `pair.class' does not use `static.make'.
Instead, to set the first half, `car' of the CONS.CELL it uses
`.setfirst', and to set the second half, `cdr', it uses `.setbf'.

One point is worth noting again. Only the variables that were given
value in the STATIC line will be visible in the run-time part of the
class instance; e.g., PAIR.O. The CONS.CELL variable, on the other
hand will not.

The PAIR.CLASS responds to following messages:

`get ; getx ; indirect'
     Both GET and GETX will output the first part of the `pair.o'. It
     is natural to use GET, if pair object contains only one value
     (the other is an empty list). If we are using pair object to
     hold two distinct values (like X, and Y coordinates in the
     plane), then use GETX, to avoid the confusion.

`set VALUE;  setx VALUE'
     Both will set (change) the value of the first part of `pair.o'
     to be the VALUE.

`gety'
     Will output the value of the second part of the `pair.o'.
     Meaningful only if you use object to hold two values.

`sety VALUE'
     will set (change) the value of the second part of `pair.o'.

`raw'
     Will output the raw value of the `pair.o'. Often the result will
     not be what one expects; e.g.; if you created the object with:

          define "pair1 (object.maker "pair.class "x "y)
     The result printed by Logo will be:
          show send "pair1 "raw
          [x ]

     This is just the way Logo print-er sees the dotted pair
     structure, it does not mean that the Y part has vanished. You
     can check this with the next message.

`p2l'
     This will output first and second parts of `pair.o', formated as
     a list of two objects. (P2L stands for; pair to list)

          show send "pair1 "p2l
          [x y]

The main difference between RAW, and P2L is that RAW hands you the
pointer to the actual object itself, while P2L only outputs the coppy
of the object. From the standpoint of OOP RAW would probably be
considered illegal, because it opens the backdoor to the private
storage.

swap.pair
---------

`swap.pair.class' is based on the PAIR.CLASS, and adds only one new
message to it--SWAP. It can be used instead of the PAIR.CLASS if you
need to swap two parts of static storage.

     to swap.pair.class :xinit [:yinit []]
     static [[pair.o [(object.maker "pair.class :xinit :yinit)]]]
     lambda :msg
     local "tmp
     op case [
        [first bf :msg]
        [[swap]
         [make "tmp send "pair.o "gety]
         [ignore (send "pair.o "sety send "pair.o "get)]
         [(send "pair.o "set :tmp)]]
        [[type] ["swap.pair.object]]
        [else [delegate "pair.o :msg]]]
     end

`swap'
     Swaps the first and butfirst parts of the PAIR object, and
     returns the first part.

border class
------------

`border.class', although listed here as a simple base class, is very
different, and the explanation of WHAT, and HOW it does (whatever it
is that it does), would be only confusing here. We shall get back to
it in the *tutorial*, when explaining the QUEENS8 class.

Very broadly; it serves as a stop object. Let's say we have several
objects of the same kind, calling each other to perform some task.
The task is supposedly finished when the last object in the line has
to call the next object. An instance of the `border.class' can be
used as one such NEXT object. It will stop the execution, (possibly)
display the message it was initialized with, and (possibly) call some
previous objects to collect results of computation from them.

It is very difficult, to determine even what messages does the
`border.object' respond to, just by looking at its code:

     to border.class :text [:objects []] [:msgs []]
     static [[text.o [(object.maker "pair.class :text)]]
             [objmsg.pairs [(object.maker "pair.class :objects :msgs)]]]
     lambda :message
     local [self msg]
     make "self first :message make "msg bf :message
     case [
        [first :msg]
        [[exit.outer] [op "false]]
        [[erase.object] [op delegate "base.object :msg]]
        [else [
           ;; output text and all results of terminal object msg calls
           ;; use 'self to send msg 'exit.outer to border.class object -- as a
           ;; flag to break out of the outer loop (see queens8.class)
           op se send "text.o "get ~
           (map [[x y] [op apply "send se :x :y]]
                send "objmsg.pairs "get send "objmsg.pairs "gety)]]]
     end

`exit.outer'
     This is the only private method. It will output the word "false,
     which can be used to break the execution of an outer loop (as in
     `while').

`erase.object'
     The only other message `border.object' will catch and delegate
     to the `base.object'.

There are many other messages that border object can receive, but for
their dispatching, it will use a sort of multiple
inheritance--calling different objects, with different messages.

This is probably more than enough about `border.class' for now.

counter class
-------------

This is the first class that we used so far (apart from BORDER.CLASS,
which was not explained), that not only sets up its private storage
(INIT.VAL), but also sets up one private (virtual) object to handle
the storage getting and setting tasks.

The novelty is also the IF NOT ... line, before the STATIC line. That
line works as in any ordinary Logo procedure--stops the execution of
a procedure if the variable :INIT does not contain a number. The
point to understand is; which procedure is stopped? The object
created by the `counter.class', or the `object.maker'? Answer is very
simple--this line belongs to the compile-time part of the class,
therefore it must be the `object.maker' that is stopped. The IF NOT
... line will not appear in the object at all.

     to counter.class :init
     if not numberp :init [(send "base.object "error
                                 [Input must be a number!])]
     static [[init.val :init]
             [pair.o [(object.maker "pair.class :init)]]]
     lambda :msg
     op case [
        [first bf :msg]
        [[inc] [(send "pair.o "set sum (send "pair.o "get) 1)]]
        [[dec] [(send "pair.o "set (send "pair.o "get) - 1)]]
        [[reset] [(send "pair.o "set :init.val)]]
        [[type] ["counter.object]]
        [else [delegate "pair.o :msg]]]
     end

If we define an instance with:

     define "c1 (object.maker "counter.class 0)
and check the code with:
     show fulltext "c1

     to c1 :msg
     local [init.val pair.o]
     make "init.val gprop "g57.g58.counter.class "init.val
     make "pair.o gprop "g57.g58.counter.class "pair.o
     op run [
        local "#target make "#target run [first bf :msg]
        ifelse.tf memberp :#target [inc]
           [(send "pair.o "set sum (send "pair.o "get) 1)]
           [ifelse.tf memberp :#target [dec]
              [(send "pair.o "set (send "pair.o "get) - 1)]
              [ifelse.tf memberp :#target [reset]
                 [(send "pair.o "set :init.val)]
                 [ifelse.tf memberp :#target [type]
                    ["counter.object]
                    [delegate "pair.o :msg]]]]]
     end

You have probably notice that the `case' has disappeared; `c1' code
has been compiled. Secondly, there are two static variables created;
one is the initializing input. We can check its contents with:

     show gprop "g57.g58.counter.class "init.val
     0

This, as expected, prints 0. The next one is more interesting:

     show gprop "g57.g58.counter.class "pair.o
     [[msg]
      [local [pair.o]]
      [make "pair.o gprop "g57.g59.pair.class "pair.o]
      [op run
          [local "#target make "#target run [first bf :msg]
          ifelse.tf memberp :#target [get getx]
             [first :pair.o]
             [ifelse.tf memberp :#target [set setx]
                [.setfirst :pair.o last :msg first :pair.o]
                [ifelse.tf memberp :#target [gety]
                   [bf :pair.o]
                   [ifelse.tf memberp :#target [sety]
                      [.setbf :pair.o last :msg bf :pair.o]
                      [ifelse.tf memberp :#target [raw]
                         [:pair.o]
                         [ifelse.tf memberp :#target [p2l]
                            [list first :pair.o bf :pair.o]
                            [ifelse.tf memberp :#target [type]
                               ["dotted.pair.object]
                               [delegate "base.object :msg]]]]]]]]]]

I have formatted this output, as it would be very difficult to read
it as one line only.

If you compare this to the code of the `pair.class', you will see
that they are the same (except for the `case' form being compiled
into standard Logo code). What this means is--object `c1' has created
its private instance of the `pair.class', instead of just its private
static storage. The rational is very simple. `c1' does not care how
is the value of the counter actually accessed or changed in memory.
This is delegated (inherited) from the pair.class. Therefore object
`c1' can only read or alter its contents, by asking (sending
messages) to the `pair.o' to do so.

If you want to see what is the current value of the counter, you have
to check the `pair.o' static storage, not the `c1' storage. Let's
perform this test:

     pr send "c1 "inc
     1
     pr send "c1 "inc
     2

Now we will check the `pair.o'bject's static storage:

     show gprop "g57.g59.pair.class "pair.o
     [2]

This should be enough to convince you.

Note that it is only the `c1' object that exists as a globally
defined procedure. `pair.o' is just a list value (that Logo knows how
to execute) stored in g57.g58.counter.class property list.

`counter.class' responds to following messages:

`inc'
     Increments the counter, and outputs its incremented value.

`dec'
     Decrements the counter, and outputs its decremented value.

`reset'
     Resets the value of the counter to be the INIT.VAL, and outputs
     that value.

The rest of the messages are delegated to the `pair.o', which means
that the counter can also respond to messages GET, SET ... Actually
to all messages that an instance of a PAIR.CLASS knows how to respond
to.

This is a brief example of interaction with the `c1' object:

     pr send "c1 "reset
     0
     pr send "c1 "inc
     1
     pr send "c1 "inc
     2
     pr send "c1 "dec
     1
     pr send "c1 "get
     1
     pr send "c1 "getx
     1
     show send "c1 "gety
     []
     show send "c1 "reset
     0
     show send "c1 "type
     counter.object

     show send "c1 "increment
     ERROR: increment not understood by object: c1

     show send "c1 "erase.object
     [18599 191950]

The last one; ERASE.OBJECT has erased the `c1' object, and all of its
static storage (including the `pair.o' and its static storage) from
the memory. The output is showing the garbage collector's statistics.
Numbers indicate the number of nodes in use now, and before call to
Logo `GC'.

rewinding counter class
-----------------------

REWINDING.COUNTER.CLASS is a simple modification of a
`counter.class', from which it inherits most of its methods. It is
based on the model of the old analog mileage counter in cars. It
starts with some :INIT value, increments the counter by 1 to :LIMIT
value, and then restarts with :INIT value again.

     to rewinding.counter.class :init :limit
     if not numberp :limit [(send "base.object "error
                                 [Input must be a number!])]
     static [[init.val :init] [rewind :limit]
             [counter.o [(object.maker "counter.class :init)]]]
     lambda :msg
     case [
        [first bf :msg]
        [[inc] [op ifelse (send "counter.o "get) < :rewind
                          [(send "counter.o "inc)]
                          [(send "counter.o "reset)]]]
        [[type] [op "rewinding.counter.object]]
        [[dec] [op delegate "base.object :msg]]
        [else [op delegate "counter.o :msg]]]
     end

During compilation of the REWINDING.COUNTER.CLASS, the `object.maker'
builds the global object of REWINDING COUNTER TYPE, which builds its
own private virtual object of the COUNTER TYPE, which builds its own
private object of the PAIR TYPE, which will ultimately hold the value
of the counter.

At this stage you can begin to appreciate the `black box' metaphor
for the OOPS. Can you tell, by examining the code of
`rewinding.counter.class', whether its instances care which static
memory access class is used; `bucket.class', or `pair.class'? The
answer is no--they do not. And the matter of fact is that most of the
classes in this chapter were developed (based on `bucket.class'),
before the `pair.class' was implemented. To have the whole system use
the `pair.class' instead of `bucket.class', I only had to alter those
classes that directly use either bucket or pair class (the change was
only in the different name used for memory access class). Of the
classes you have seen so far, that would be only the `counter.class'.
REWINDING.COUNTER, does not require any changes. (1)

Here are some examples of interaction with one REWINDING.COUNTER
object:

     define "rc1 (object.maker "rewinding.counter.class "x 3)
     ERROR:  Input must be a number!

     define "rc1 (object.maker "rewinding.counter.class 0 "x)
     ERROR:  Input must be a number!

     define "rc1 (object.maker "rewinding.counter.class 0 3)

     pr send "rc1 "get
     0
     pr send "rc1 "inc
     1
     pr send "rc1 "inc
     2
     pr send "rc1 "inc
     3
     pr send "rc1 "inc
     0
     pr send "rc1 "inc
     1

     pr send "rc1 "dec
     ERROR: dec not understood by object: rc1

     pr send "rc1 "erase.object
     29882 255950

---------- Footnotes ----------

(1) All of this is true for the classes developed to use the
BUCKET.CLASS. However classes that were written to exploit the dual
storage capacity of PAIR.CLASS, can not switch back to the
BUCKET.CLASS. These are BORDER.CLASS,
DOUBLE.END.CLASSCONTAINER.CLASS, STACK.CLASS ...

container class
---------------

The `container.class' is a simple class that works on lists only.
Most of the work is done directly by the underlying `pair.class'. The
`container.class' itself only adds some common list operations.

     to container.class
     static [[list.o [(object.maker "pair.class [])]]]
     lambda :msg
     op case [
        [first bf :msg]
        [[first indirect] [first send "list.o "get]]
        [[fput]
         [(send "list.o "set fput first bf bf :msg send "list.o "get)]]
        [[bf butfirst]
         [ignore (send "list.o "sety first send "list.o "get)]
         [(send "list.o "set bf send "list.o "get)]]
        [[last] [last send "list.o "get]]
        [[bl butlast]
         [ignore (send "list.o "sety last send "list.o "get)]
         [(send "list.o "set bl send "list.o "get)]]
        [[lput] [(send "list.o "set lput last :msg send "list.o "get)]]
        [[empty? emptyp] [emptyp send "list.o "get]]
        [[count] [count (send "list.o "get)]]
        [[member? memberp] [memberp last :msg send "list.o "get]]
        [[member] [member last :msg send "list.o "get]]
        [[flush] [(send "list.o "set [])]]
        [[type] ["container.object]]
        [else [delegate "list.o :msg]]]
     end

`container.class' responds to following messages:

`first ; indirect'
     outputs the first element of the list (list.o)

`fput VALUE'
     inserts the VALUE to the front of the list, and outputs the new
     list

`bf ; butfirst'
     removes the first element from the list, and outputs the new
     list. First element is saved in the butfirst part of the pair,
     and can be retrieved with GETY

`last'
     outputs the last element of the list

`bl ; butlast'
     removes the last element from the list, and outputs the new
     list. Last element is saved in the butfirst part of the pair,
     and can be retrieved with GETY

`lput VALUE'
     inserts the VALUE to the back of the list, and outputs the new
     list

`empty? ; emptyp'
     outputs true if the list is empty

`count'
     outputs the number of top-level elements in the list

`member? ; memberp VALUE'
     outputs TRUE if the VALUE is a member of the list

`member VALUE'
     outputs the part of the list starting with VALUE. If VALUE is
     not a `meberp' of the list, outputs empty list.

`flush'
     empties the list, and outputs it ([])

Here are some examples of interaction with one CONTAINER object:

     define "cont1 (object.maker "container.class)

     show send "cont1 "get
     []

     show (send "cont1 "fput 3)
     [3]
     show (send "cont1 "fput 2)
     [2 3]
     show (send "cont1 "fput 1)
     [1 2 3]
     show (send "cont1 "lput "a)
     [1 2 3 a]
     show (send "cont1 "lput "b)
     [1 2 3 a b]
     show send "cont1 "bf
     [2 3 a b]
     show send "cont1 "gety
     1
     show send "cont1 "bl
     [2 3 a]
     show send "cont1 "gety
     b
     show send "cont1 "count
     3
     show (send "cont1 "member 3)
     [3 a]
     show send "cont1 "get
     [2 3 a]
     show send "cont1 "flush
     []
     show send "cont1 "empty?
     true
     show (send "cont1 "set [1 2 3 4 5])
     [1 2 3 4 5]

     show send "cont1 "size
     ERROR: size not understood by object: cont1

stack class
-----------

Stack is a *first in last out* structure, based on `container.class'.
Practically all of the work is carried out by an instance of
CONTAINER.CLASS--STACK.CLASS only renames some of the list
operations, and adds checks for empty list.

     to stack.class
     static [[holder.o [(object.maker "container.class)]]]
     lambda :msg
     op case [
        [first bf :msg]
        [[push] [(send "holder.o "fput first bf bf :msg)]]
        [[pop]
         [ifelse.tf send "holder.o "empty?
                    [(send "holder.o "error [Stack is empty])]
                    [ignore send "holder.o "bf send "holder.o "gety]]]
        [[top]
         [ifelse.tf send "holder.o "empty?
                    [send "holder.o "error [Stack is empty]]
                    [send "holder.o "first]]]
        [[size] [send "holder.o "count]]
        [[type] ["stack.object]]
        [else [delegate "holder.o :msg]]]
     end

`stack.class' responds to following messages:

`push VALUE'
     pushes the VALUE onto the stack. VALUE becomes the first element
     of the underlying list structure.

`pop'
     removes the first item from the stack (list), and outputs that
     value. Displays error message if the stack is empty.

`top'
     outputs the first element of the stack, but does not remove it.
     It is an error if the stack is empty.

`size'
     outputs the size of the stack (count of the list)

Here are some examples of interaction with one STACK object:

     define "stack1 (object.maker "stack.class)

     show (send "stack1 "push "a)
     [a]
     show (send "stack1 "push "b)
     [b a]
     show (send "stack1 "push "c)
     [c b a]
     show send "stack1 "pop
     c
     show send "stack1 "size
     2
     show send "stack1 "get
     [b a]
     show send "stack1 "pop
     b
     show send "stack1 "top
     a
     show send "stack1 "empty?
     false
     show send "stack1 "pop
     a
     show send "stack1 "pop
     ERROR:  Stack is empty

     show send "stack1 "erase.object
     [31313 207950]