Next: 2.4 Type Annotations
Up: 2 Language Reference
Previous: 2.2 Expressions
  Contents
Subsections
METHODS in Slate are basically annotated
block closures (documented in
), coupled
with annotations of the objects' roles that dispatch to them.
Method definition syntax is handled relatively separately from normal
precedence and grammar. It essentially revolves around the use of
the reserved character ``@''. If any identifier in a
message-send argument position is found to contain the character,
the rest of the same send is examined for other instances of the symbol,
and the whole send-expression is treated as a template. The parser
treats the expression or identifier to the right of the @
characters as dispatch targets for their argument positions; the actual
objects returned by the expressions are annotated with a role for
their positions.
After the message-send template, there is expected a block expression
of some kind, whether a literal or an existing block. Whichever is
specified, the parser creates a new block out of it with adjustments
so that the identifiers in the dispatching message-send become input
slots in the closure. The block should be the final expression encountered
before the next stop (a period).
There is a further allowance that an input slotname specifier may
be solely an underscore (but not an underscore followed by anything
else), in which case the argument to the method at that position is
not passed in to the block closure.
This syntax is much simpler to recognize and create than to explain.
For example, the following are a series of message definitions adding
to boolean control of evaluation:
-
- _@True ifTrue: block ifFalse: _ [block value].
_@False ifTrue: _ ifFalse: block [block value].
bool@(Boolean traits) ifTrue: block
"Some sugaring for ifTrue:ifFalse:."
[
bool ifTrue: block ifFalse: []
].
The first two represent good uses of dispatching on a particular individual
object (dispatching the ignored symbol ``_'' to True
and False, respectively) as well as the syntax for disregarding
its value. Within their blocks, block refers to the named
argument to the method. What's hidden is that the block given as the
code is re-written to include those arguments as inputs in the header.
The latter method is defined in terms of the first two, since True
and False both delegate to Boolean traits (the
object carrying the common behavior of the boolean objects).
The specialized syntax using the ``@'' special has an
equivalent in regular Slate syntax which is often useful for generating
new methods dynamically in a non-ambiguous way. This is a reflective
call on the interpreter to compile a method using a certain symbolic
name and a sequence of objects that are used for dispatching targets.
For example:
-
- [| :x :y | 5] asMethod: #+ on: {2. 2}.
and
-
- _@2 + _@2 [5].
are equivalent (while not recommendable) expressions. This raises
the question of a place-filler for an argument position which is not
dispatched. In that case, Slate provides a unique primitive NoRole
for this purpose, which provides an analogous role to Nil:
NoRole cannot be dispatched upon. Essentially, this means
that the following method definition:
-
- c@(Set traits) keyAt: index
[
c array at: index
].
is semantically equivalent to:
-
- c@(Set traits) keyAt: index@NoRole
[
c array at: index
].
and furthermore to:
-
- [| :c :index | c array at: index] asMethod: #keyAt:
on: {Set traits. NoRole}.
Message dispatch in Slate is achieved by consulting all of the arguments
to that message, and considering what roles they have pertaining to
that message name and their position within the message-send. During
the dispatch process, more than one method is often discovered as
a potential candidate. The most specific candidate is chosen
as soon as its place in the order is determined.
The algorithm achieves a full ordering of arguments: the specificity
of the first argument counts more than the second, the second more
than the third, and so on. However, where normal multiple dispatch
uses the most specific supertype to determine specificity (or rather,
the most specific parameter type of which the argument is a subtype),
specificity is instead interpreted as DISTANCE in the directed
graph of delegations, starting from the argument as the root.
The DISTANCE notion has the following properties:
- It is determined by a depth-first traversal over the delegate slots,
considering most-recently-added delegates before previously-added
ones.
- Delegations that lead to cycles are not traversed.
- Repeated finds of a same method do not alter the distance value for
it; the first one found is retained.
- The closer the DISTANCE of the role to the argument, the
more specific it is.
The resulting dispatched method satisfies the property that: for any
of the arguments, we can find the method on some role reachable by
traversing delegations, and that is the closest such method we can
find (where former arguments count as being ``closer'' than any
subsequent arguments), where NoRole behaves like an ``omega
distance'', as far away as possible.
Because Slate's methods are not centered around any particular argument,
the resending of messages is formulated in terms of giving the method
activation itself a message. The simplest type of resend is resend,
which finds the next most-applicable method and invokes it with the
exact same set of arguments. The result of resend is the
returned result of that method.
- methodName findOn: argumentArray
- locates the method for
the given symbol name and group of argument objects.
- methodName findOn: argumentArray after: aMethod
- locates
the method following the given one with the same type of arguments
as above.
- methodName sendTo: argumentArray
- is an explicit application
of a method, useful when the symbol name of the method needs to be
provided at run-time.
- sendWith:,
- sendWith:with: and sendWith:with:with:
take one, two, and three arguments respectively as above without creating
an array to pass the arguments in.
- methodName sendTo: argumentArray through: dispatchArray
- is
an extra option to specify a different signature for the method than
that of the actual argument objects.
The multiple dispatch system has an extended dynamic signature form
which can be used to give a ``subjective'' or ``layered''
customization of the Slate environment. This is an implementation
and slight modification of the Us language features conceived of by
the Self authors[Smith 96].
- Slate dispatch signatures are ``enlarged'' to support two implicit
endpoints: one before the first argument and one after. We refer to
the first role as an ``advisor'' or Layer, and to the
second as a Subject or ``interleaver''. The layer role,
being ``to the left'' of the explicit argument positions, has
higher precedence than any of them; the subject role has a correspondingly
opposite role: it has the lowest precedence of all.
- Two primitive context-handling methods were added to support invoking
code with a different object used for one of these new roles. What
happens is that you execute a block [] seenFrom: someSubject
in order to make all methods defined within dispatched with that object
as the subject, and all methods looked up in that context (or any
other context ``seen from'' that object) used with that subject
in the dispatch.
The effect of combining these two mechanisms is that there is a means
for the user to dynamically (and transparently) extend existing libraries.
The Layer usage has a more ``absolute'' power to override,
since without dispatching on any other arguments, a method defined
in a layer will match a message before any other can. The Subject
usage has a more fine-tuned (or weaker, in another sense) ability
to override, since without any other dispatching, a method defined
with a certain subject will never be called. However, taking an existing
method's signature and defining a customized version with a subject
will allow customizing that specific method without affecting any
other method with that selector.
- Methods defined with a special subject or layer persist with
those objects, since they are just dispatch participants.
- Resending messages works just the same within subjective methods as
in normal methods; the same dispatch mechanism is in effect, so the
ability to combine or extend functionality is available.
- Nesting subjective scopes has a dynamic scoping effect: the
actions taken within have run-time scope instead of corresponding
exactly to how code is lexically defined. This gives the compositional
effect that should be apparent when viewing nested subjective scopes.
- Methods defined in non-subjective contexts have no subject or layer
rather than any ``default'' subject: they are for most purposes,
``objective''.
- Subject
- the type of object which provides an appropriate
handle for subjective interleaving behavior in dynamically overriding
or extending other methods' behaviors.
- Layer
- the type of object which provides an appropriate
handle for subjective layering behavior in dynamically overriding
or extending other methods' behaviors.
- [] seenFrom: aSubject
- executes the contents of the
block with the given Subject dynamically affecting the execution
of the expressions.
- aLayer layering: []
- executes the contents of the
block with the given Layer dynamically affecting the execution
of the expressions.
- [] withoutSubject
- executes the contents of the block
without any subject.
- [] withoutLayers
- executes the contents of the block
without any layer.
The mechanism in Slate for specifying optional input arguments uses
optional keywords for a syntax. They can be added to a method
definition, a message-send, or a block header equally. Also, optional
keywords can apply to unary, binary, and keyword message syntaxes
equally.
An optional keyword argument is given by ``&argName: someValue'',
and following keywords that have the &-prefix will be collected
into the same message-send. A following non-optional keyword will
be treated as a new message-send.
A block can declare optional input keywords in its block header, using
``&argName'' as an input variable declaration, called
with the normal convention, whenever the block is invoked with a message-send.
Next: 2.4 Type Annotations
Up: 2 Language Reference
Previous: 2.2 Expressions
  Contents
The Slate Project
2003-12-05