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:
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:
Message dispatch in Slate is acheived 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:
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.
Input and local slots' types can be specified statically for performance or documentation reasons, if desired. The special character ``!'' is used in the same manner as the dispatch annotation ``@'', but type-annotations can only occur within a block closure's header. The type system and inference system in Slate is part of the standard library, and so is explained later.
Preceding any selector with a back-tick (`) will cause it to be applied to the parsed pre-evaluated form of its arguments. This provides access to syntax-level methods at run-time and compile-time.
Slate's parser produces syntax trees which are trees of objects with various attributes, so there is some difference from the Lisp family of languages in that simple lists are not the limit of the expression's parsed format.
A few of the macro-methods we have found appropriate already are `quote and `unquote, which pass as their run-time result the syntax-level shifted versions of their expressions.
`quote causes the surrounding expression to use its quoted value as the input for even normal methods.
`unquote results in an inversion of the action of `quote, so it can only be provided within quoted expressions. Lisp macro system users will note that this effectively makes `quote the same as quasi-quotation.
In experience with Lisp macros, nested quotation is often found necessary. In order to adequately control this, often the quotation prefix symbols have to be combined in non-intuitive ways to produce the correct code. Slate includes, as an alternative, two operations which set a label on a quotation and can unquote within that to the original quotation by means of referencing the label.
Most users need time to develop the understanding of the need for higher-order macros, and this relates to users who employ them. For reference, a Lisp book which covers the subject of higher-order macros better than any other is On Lisp[3]. However, it's also been said that Lisp's notation and the conceptual overhead required to manage the notation in higher-order macros keeps programmers from entering the field, so perhaps this new notation will help.
The operators are expr1 `quote: aLiteral and expr2 `unquote: aLiteral, and in order for this to work syntactically, the labels must be equal in value and must be literals. As well, the unquoting expression has to be a sub-expression of the quotation. The effect is that nesting an expression more deeply does not require altering the quotation operators to compensate, and it does indicate better what the unquoting is intended to do.
`evaluate provides compile-time evaluation of arbitrary expressions.
`with:as: is a protocol for transparent substitution of temporary or locally-provided proxies for environment values and other system elements. This should provide an effective correspondent of the functionality of Lisp's "with-" style macros.
Macros must be dispatched (if at all) upon the traits of expressions' syntactic representation. This introduces a few difficulties, in that some familiarity is needed with the parse node types in order to name them. However, only two things need to be remembered: