.c	Thursday  Dec 1,1983  23:05  LQ+4D.17H.12M.16S.  -*- Bolio -*-

.chapter "The Flavor Facility"

.section Introduction

Languages such as Smalltalk and Act-1 are designed to encourage a
style of programming called 2object-oriented* programming.
lan{Lispm} offers a facility for object-oriented programming as
well; it is called the term_i{Flavor System}, or just flavors.
lan{Nil} offers a more primitive version of flavors than is
available on the Lisp Machine, but unless you do quite complicated
things with flavors, you will probably never notice the difference.

.subsection Object-oriented Programming

Suppose you were writing a file system.  You might have several different
types of files, including, for example, binary files and text files.  If you
wrote a program to print files on a user's terminal, and you wanted it to
print ASCII characters when the user printed a text file, but octal numbers
when the user printed a binary file, you might implement it as follows:
.lisp
(typecase file
   (binary (octally-print file))
   (text (ascii-print file)))
.end_lisp
That is, you might dispatch off the type of the file, calling the appropriate
function to print the file.  It might be nicer, however, to keep the
information about how the file should be printed 2with the file itself*.
That is, the method used for printing itself could be part of the information
contained in each file; we could simply decide that every type of file we
will support in our operating system will know how to perform certain
operations, and we could specify printing on a terminal to be one of them.
Then we would implement the above as
.lisp
(send file :print-contents)
.end_lisp
where 3:print-contents* is the name of a method that could be
specified for each type of file.

On simply looking at the differences between the two samples of code, one
might notice that the second expresses much more clearly and compactly what
we are doing: printing the file.  We trust whoever defined this type of file
object to have defined a reasonable 3:print-contents* method for it, and we
don't worry any further about type-dispatching and the like.  Thus
object-oriented programming constructs can have the effect of freeing the
programmer from an extra level of detail.

This should sound familiar even to users who have not used flavors, because
it is similar to generic arithmetic in lan{Common Lisp}.  In fact,
operations that work for more than one type of object (like the imaginary
3:print-contents* above) are called 2generic operations*.

Another thing we might notice about the object-oriented way of doing things
is described by its name.  We might say somewhat fancifully that the files in
our example above have been raised from the realm of ``inanimate data'' to
being objects that can 2do* things.  A file has become an object that
knows how to print itself, and can be asked to do so.

Objects can know of things besides their methods for performing operations,
and this brings up another advantage of object-oriented programming, which is
useful even when one is not planning on implementing operations that will
work on a large class of objects.  Two objects of the same type will share
the same methods for performing an operation.  But two objects of the same
type can still have distinct state.  They can have instance variables:
variables that are local to each instantiation, in much the same way that
scoped variables are local to a function call.  For example, the file objects
we were discussing above could have variables 3:author* and
3:write-date*, and each object would have its own value for these
variables.

.subsection Object-oriented Programming Using Flavors

When we use flavors to write object-oriented code, the objects themselves are
not flavors.  They are 2instantiations* of flavors.  The flavor of an
object is actually its type.  We define a flavor using
spec_i{defflavor}.  The definition of a flavor looks like
.lisp
(defflavor 2flavor-name* 2instance-variables*
  2component-flavors*
  2option1* 2option2*... )
.end_lisp

The 2flavor-name* can be any symbol, the 2instance-variables* a
(possibly null) list of symbols (variables) and their initial values, the
2component-flavors* a list of flavors, and the 2option*s will be
described further below.  A more concrete example is:
.lisp
.setq bicycle-example page
(defflavor bicycle ((wheel-size nil) (gear-ratios nil)
		    (selected-gear nil)
		    (distance-travelled nil))
  ()
  :gettable-instance-variables
  :settable-instance-variables)
.end_lisp


The option 3:gettable-instance-variables* will cause a method that will
return the value of that instance variable to be defined for each of the
instance variables.  3:settable-instance-variables* will cause a method
that will allow us to set the value of that instance variable to be generated
for each instance variable.

If we want to create an instantiation of the flavor 3bicycle*, we use
fun_i{make-instance}:
.lisp
(setq my-bike (make-instance 'bicycle))
.end_lisp
returns
.lisp
#<BICYCLE 1287B8>
.end_lisp
or something like it.  This object can be 3describe*d:
.lisp
(describe my-bike)

The instance at address 1287B8 is of flavor BICYCLE and is 4
Q's long.  It directly or indirectly includes flavors (BICYCLE
VANILLA-FLAVOR), and is of the types (BICYCLE VANILLA-FLAVOR).
The 4 instance variables are:
  WHEEL-SIZE  NIL
  GEAR-RATIOS  NIL
  SELECTED-GEAR  NIL
  DISTANCE-TRAVELLED  NIL
NIL
.end_lisp

We can cause an instantiation of a flavor to execute a method with
3send*.  The methods created upon definition of a flavor with the option
3:settable-instance-variables* have the names of the instance
variables appended to "set-", but are in the keyword package.  Thus we
could set the value of 3wheel-size* like this:
.lisp
(send my-bike :set-wheel-size 27)
.end_lisp
The methods created on definition of a flavor with the option
3:settable-instance-variables* are the same as the names of the
variables, but are in the keyword package.  So we could get the value of
3:wheel-size* like this:
.lisp
(send my-bike :wheel-size)
27
.end_lisp

We can define methods for the flavor we've created with the function
3defmethod*.

.defun send object message &rest args
This is the basic message-passing primitive.  It should be used
instead of 3funcall*, which has been used in the past in lan{lisp
machine lisp}.
.end_defun

.defun lexpr-send object message &rest args
This is to 3send* as 3lexpr-funcall* (which is 3apply*
((apply-fun)), as it is defined now) is to 3funcall*.

There must be at least one 2arg* given, and the last one must be
either a list or a vector.  The object is sent 2message* with
arguments of all of the other 2args* followed by all the elements
of the last 2arg*.
.end_defun

.defspec send-forward object message {arg}*
This is only valid within the lexical scope of a 3defmethod*
definition.

Let the flavor which this method was defined on be called 2flav*.
3send-forward* then does a 3send*, but starts searching for
methods to handle 2message* after 2flav*.

n.b. 3send-forward* is neither as efficient as it should be nor as
efficient as one would like, yet.  Note that it can be used to acheive
many of the same effects as method combination.
.end_defspec

.defspec lexpr-send-forward object message {arg}*
Like 3lexpr-send*, but does 3send-forward*.
.end_defspec

.defun make-instance flavor-name &rest keyworded-arguments
This is the primary instantiation function.  The
2keyworded-arguments* are alternating keywords and values.
Typically, they specify initial values for the instance variables
which are initable (as specified with the
3:initable-instance-variables* option to 3defflavor*).  They
may also be arbitrary keywords which are checked for validity against
those specified with the 3:init-keywords* option to
3defflavor*, which (merged with the 3:init-plist*
specification to 3defflavor*) will be passed as arguments to the
3:init* method of the flavor.
.end_defun


.defspec defflavor flavor-name instance-variables included-flavors options...
.end_defspec

2flavor-name* is the name of the flavor being defined.  After it
is defined, it is acceptable as a second argument to 3typep*
((typep-fun)), which will return (truth) if given a second
argument of 2flavor-name* and a first argument of an instantiation
of 2flavor-name*, or any other flavor which directly or indirectly
includes 2flavor-name*.

2instance-variables* is a list of instance variables or lists of
instance variables and forms to eval to obtain their initial values.
These are not necessarily all of the instance variables of
the instance;  some may be inherited from other flavors which
2flavor-name* is being built from.  However, compiled flavor
methods for 2flavor-name* may not know about those inherited
instance variables, so if you "know" that a flavor is going to have
certain variables and need to use them, you should include them here.
(Note that in the current lan{nil} instance variable inheritance is
performed when the 3defflavor* form is compiled, so one will not
receive a diagnostic about this.  The inheritance will be deferred in
in some later release, however, to provide for other features, including the
ability to not have the component flavors of 2flavor-name* defined
when the 3defflavor* is being compiled or interpreted.)

If an atomic instance variable is specified in the instance variables
list, then the instance variable is initialized "unbound" by
3make-instance* (assuming no initialization was specified with
3make-instance*).  This will cause an unbound variable reference
in the lan{nil} interpreter;  external ("outside accessible")
references will just pick out the unbound pointer, as will compiled
references to the instance variable, and probably cause some spastic
behavior later.

Otherwise, the instance variable specification should be a list of the
instance variable and an initialization form, which will be evaluated to
determine the initial value.  (lan{Nil} actually does not
use 3eval*, but stores the value either as a constant, if it
self-evaluates, or as a function of no arguments which evaluates the
initialization form;  this function will be compiled when the
3defflavor* form is compiled.)

The following 3defflavor* options all deal with instance variables
which must be listed in the 2instance-variables* given for the
defflavor.  They may appear as atomic options, like
3:gettable-instance-variables* and
3:settable-instance-variables* in the 3bicycle* example
((bicycle-example)), in which case they refer to all of the
2instance-variables* of the 3defflavor*, or listed with those
hey pertain to, as in
.lisp
(defflavor frob (var-1 var-2 var-3) ()
   :gettable-instance-variables
   (:settable-instance-variables var-1 var-2))
.end_lisp
in which 3var-1*, 3var-2*, and 3var-3* are all
3:gettable*, but only 3var-1* and 3var-2* are 3:settable*.
.table 3 250 250
.item :gettable-instance-variables
Causes automatic generation of methods which will fetch the values of
the specified instance variables.  Each method name is the name of the
variable interned in the keyword package.  Thus in the 3bicycle*
example, one may send a bicycle the 3:distance-travelled* message
to find how far the bicycle has traveled.
.item :settable-instance-variables
Causes automatic generation of methods which will replace the values
of the specified instance variables.  Each method takes exactly one
argument, the new value.  The method name will be the concatentation
of "SET-" and the instance variable name, interned in the keyword
package.
.item :initable-instance-variables
This specifies which instance variables may be trivially initialized
by 3make-instance* (and 3instantiate-flavor*).  For those
which may be, it is done by specifying a keyword which is the instance
variable name interned in the keyword package followed by the value.
For example,
.lisp
(make-instance 'bicycle :wheel-size 26)
.end_lisp
.item :outside-accessible-instance-variables
This causes automatic generation of macros which access the specified
instance variables without sending messages.  In principle this is
more efficient than sending the message;  it, of course, requires that
the instance have such instance variables.  This is most useful when
the instance variables are ordered (see below);  otherwise, some
lookup has to be performed.
.item :ordered-instance-variables
The instance variables will be ordered in the instance in exactly the
order they are listed here, starting from slot 0.  This can be done to
allow super-fast external accessing, or simply because other low-level
code (like VMS assembly language routines) needs to be able to
understand the structure.
.item :special-instance-variables
don't work.
.item :functional-instance-variables
no workee.
.end_table

Other options.  Many of the instantiation-time checks are not
performed, and some are sort of meaningless in the current
implementation.  This is because this implementation 
performs all inheritance computations at eval or compile time.

.table 3 250 250
.item :required-flavors
The flavors listed are required to be included in any flavor which
includes this one.  3make-instance* is supposed to barf if that is
not the case.
.item :required-instance-variables
The instance variables listed are required to be defined by any flavor
which includes this one, and 3make-instance* is supposed to barf
if that is not the case.
.item :required-methods
Any flavor including this flavor is required to support the listed
methods.  This is alledgely checked at instantiation time.
.item :no-vanilla-flavor
Do not include 3vanilla-flavor*, as is done by default.
.item :included-flavors
Sort of like building the flavor from the named flavors, but they are
made to come last always.  2where is the inheritance-order and
vanilla-flavor insertion and this explained?*
.item :flavor-not-instantiable
This flavor is not itself instantiable.  This should be specified for
things which are not complete in themselves, but term_i{mixin
flavors}--flavors which are meant to be mixed in to provide some
aspect of other flavors.
.item :init-keywords
Allowable keywords which 3make-instance* will pass along to the
3:init* message when a flavor is instantiated.
.item :default-init-plist
Alternating keyword-values, which are supplied to the 3:init*
message when a flavor is instantiated, unless the keyword was supplied
already to 3make-instance*.
.item :documentation
ummmm
.end_table

.defspec defmethod (flavor-name message-name [message-type]) arglist body...
Defines a method 2message-name* for 2flavor*.
2message-type* is not supported, do not use it.  2arglist* is
any lambda-list acceptable to lan{nil}.  2self* will be bound
(lexically) for the evaluation of 2body*.

Lexical instance variables are correctly enclosed by the lan{nil}
interpreter in this version of lan{nil}.  The only time this can
fail is if there is any funny stuff with how the definition is being
performed, like evaluating a 3defmethod* inside the lexical
environment of another 3defmethod* or a 3defun*.  This
would not work compiled anyway.
.end_defspec

.defspec defmethod-primitive (flavor-name message-name) arglist body...
This is used to define a method 2without* interfacing to deal with
the 3self* variable or the instance variables.  The arguments
which the generated function receives will be the object, the map
vector, the message, and the other arguments.  This routine exists
primarily for primitive low-level method-generation code, as that
which might be used by spec{defstruct}.
.end_defspec

.section "System-Defined Messages"

Here are some of the messages the system uses to deal with objects
defined by 3defflavor*, and what they mean.

.defmessage :print-self 2stream* 2level* 2slashify-p*
The object should print itself to the stream 2stream*.
2level* is the recursion level of printing, and should be compared
against the dynamic value of var_i{prinlevel}.  2slashify-p*
being non-null means that the output should maybe be re-readable;  it
is being done by 3prin1* rather than 3princ*.

If you use this in a non-trivial fashion (specifically, if the object
will be printed in a non-atomic fashion), then it might be reasonable
to define methods for the pretty-printer using the 3:pp-dispatch*
and 3:pp-anaphor-dispatch* methods, and define the
non-pretty-printing 3:print-self* method in terms of how the
pretty-printing is performed.  This is described in
ref{Pretty-Print}.
.end_defmessage

.defmessage :equal 2other-object*
The method should return (true) if its object is 3equal* to
2other-object*, (false) if it is not.  2other-object* will
be of the exact same type as the object receiving the message (a
consequence of the formal definition of fun_i{equal},
(equal-fun)).  This message is also used by 3eql* ((eql-fun))
on numerical types which are not "primitive" lan{nil} data types.
.end_defmessage

.defmessage :sxhash
The object should return a hash encoding of itself, such that two
objects which are 3equal* have the same hash.  See the description
of 3sxhash*, (sxhash-fun), for the semantics which must be
enforced, and note also the default 3:sxhash* method,
(vanilla-flavor-sxhash-method).
.end_defmessage

.defmessage :eval
Allows extending the evaluator in strange and wondrous ways to handle
evaluation of non-list forms.  Note that certain types which are
defined to self-evaluate do so by special case checks in the
interpreter, so one cannot change the evaluation behaviour of those
types.  The compiler can't handle these extensions however.
.end_defmessage

.defmessage :funcall argument-vector
This is what happens by default when a 3funcall* is performed on
an instance.  2argument-vector* is a stack vector
((stack-vector-section-page)) of the arguments.
.end_defmessage

.defmessage :describe ?arguments?
This is what is used by the 3describe* function
((describe-fun)).
.end_defmessage

.defmessage :exhibit-self stream
.defmessage1 :select-nth n
.defmessage1 :store-nth n value
These are used by the 3exhibit* function ((exhibit-fun)) to
define how exhibition is performed on objects of the given type.
Basically, exhibition is initiated by sending the object a
3:exhibit-self* message;  it should respond by printing out the
appropriate information, and returning the number of "slots" or
"indices" which it includes.   (Try exhibiting various lan{nil} objects
to see the format;  do 2not* include the clear-screen in the
display.  The indices printed out in the initial display are printed
by this method.)  Then, the object will be sent (as the user interacts)
3:select-nth* and 3:store-nth* messages to select and store
the corresponding components.  Generally, there is no need to define
such a method for ordinary flavors, as the method inherited from
3vanilla-flavor* will show the instance variable names etc.
.end_defmessage

.defmessage :pp-dispatch format-description?
.defmessage1 :pp-anaphor-dispatch
These are used by the lan{nil} pretty-printer ref{Pretty-Print}.
3:pp-dispatch* is used to control formatting;  to use this you
will need to consult the pretty-printer documentation.
3:pp-anaphor-dispatch* is used to detect circularities in the
structure being printed;  all that is normally needed is to call the
function 3pp-anaphor-dispatch* on each of the components which
will be printed by the 3:pp-dispatch* method.  These methods
should be defined in pairs, so that they refer to the same set of
components.
.end_defmessage

.section "Message Defaults"

Here are some of the messages provided by 3vanilla-flavor*, and
what they do.

.defmethod vanilla-flavor :print-self stream level slashify-p
Prints something vaguely informative.
.end_defmethod

.defmethod vanilla-flavor :get-handler-for message-name
Returns the handler function for the message 2message-name*, or
(false).  In lan{nil}, this is necessarily of type
3compiled-function*.
.end_defmethod

.defmethod vanilla-flavor :operation-handled-p message-name
Returns a non-null value if the object supports a message
2message-name*, (false) otherwise.
.end_defmethod

.defmethod vanilla-flavor :send-if-handles message &rest args
If the object supports 2message*, then it is sent that message
with arguments of whatever 2args* were passed;  otherwise,
(false) is returned.
.end_defmethod

.defmethod vanilla-flavor :which-operations
A list of all of the messages which the object handles is returned.
This is computed dynamically and cached on a per-flavor basis.
.end_defmethod

.defmethod vanilla-flavor :equal
By default, two objects are 3equal* only if they are 3eq*.  If
the object has interesting criterial components, it must define an
3equal* message to compare them.
.end_defmethod

.defmethod vanilla-flavor :sxhash
The default 3:sxhash* simply returns a hash computation on the
name of the flavor.  The reason for this is that if two objects are
3equal*, their 3sxhash*es 2must* be 3equal*.  So, if
the object does anything interesting for the 3:equal* message, it
should probably define a compatible 3:sxhash* message so that
different objects will hash differently.
.end_defmethod

.defmethod vanilla-flavor :exhibit-self stream
.defmethod1 vanilla-flavor :select-nth n
.defmethod1 vanilla-flavor :store-nth n value
The default exhibition method displays the all of the instance
variables of the instance, and their values.  The select and store
methods just allow one to fetch and modify the variables by index.
.end_defmethod

.defmethod vanilla-flavor :pp-dispatch format-description?
The default 3:pp-dispatch* method pretty-prints the object the way
it prints (via 3:print-self*), and treats it as atomic.  If you
define a 3:print-self* method for something, the
3:pp-dispatch* method may not function as desired, in that it will
not do any formatting of the components.
.end_defmethod

.defmethod vanilla-flavor :pp-anaphor-dispatch
The default 3:pp-anaphor-dispatch* method does nothing, on the
grounds that the 3:pp-dispatch* method will not be printing any
components.
.end_defmethod

