next up previous contents
Next: 2.3 Methods Up: 2 Language Reference Previous: 2.1 Objects   Contents

Subsections

2.2 Expressions

Expressions in Slate mostly consist of message-sends to argument objects. The left-most argument is not considered an implicit receiver as it is with most message-passing languages, however.

An important issue is that every identifier is case-sensitive in Slate, that is, there is a definite distinction between what AnObject, anobject, and ANOBJECT denote even in the same context. Furthermore, the current implementation is whitespace-sensitive as well, in the sense that whitespace must be used to separate identifiers in order for them to be considered separate. For example, ab+4 will be treated as one identifier, but ab + 4 is a message-send expression.

There are three basic types of messages, with different syntaxes and associativities: unary, binary, and keyword messages. Precedence is determine entirely by the syntactic form of the expression, but it can of course be overridden by enclosing expressions in parentheses. An implicit left-most argument can be used with all of them. The default precedence for forms is as follows:

  1. Literal syntax: arrays, blocks, block headers, statement sequences.
  2. Unary message-sends.
  3. Binary message-sends.
  4. Keyword message-sends.
A concept that will be often used about message-sends is that of the name of a message, its SELECTOR. This is the symbol used to refer to the message or the name of a method that matches it. Slate uses three styles of selectors, each with a unique but simple syntax.

2.2.1 Unary Message-sends

A UNARY MESSAGE does not specify any additional arguments. It is written as a name following a single argument; it has a post-fix form.

Some examples of unary message-sends to explicit arguments include:

Slate> 42 print. 
'42' 
Slate> 'Slate' clone. 
'Slate'
Unary sends associate from left to right. So the following prints the factorial of 5:

Slate> 5 factorial print. 
'120'
Which works the same as:

Slate> (5 factorial) print. 
'120'
Unary selectors can be most any alpha-numeric identifier, and are identical lexically to ordinary identifiers of slot names. This is no coincidence, since slots are accessed via a type of unary selector.

2.2.2 Binary Message-sends

A BINARY MESSAGE is named by a special non-alphanumeric symbol and 'sits between' its two arguments; it has an infix form. Binary messages are also evaluated from left to right; there is no special precedence difference between any two binary message-sends.

These examples illustrate the precedence and syntax:

Slate> 3 + 4. 
7 
Slate> 3 + 4 * 5. 
35 
Slate> (3 + 4) * 5. 
35 
Slate> 3 + (4 * 5). 
23
Binary messages have lower precedence than unary messages. Without any grouping notation, the following expression's unary messages will be evaluated first and then passed as arguments to the binary message:

Slate> 7 factorial + 3 negated. 
5037 
Slate> (7 factorial) + (3 negated). 
5037
Binary selectors can consist of one or more of the following characters:

# $ %  & * - + =  / \ ? < > , ;
However, these characters are reserved:

@ [ ] ( ) { } . : ! | `

2.2.3 Keyword Message-sends

A KEYWORD MESSAGE is an alternating sequence of keywords and expressions, generally being a continued infix form. Keywords are identifiers beginning with a letter and ending with a colon. Keyword messages start with the left-most argument along with the longest possible sequence of keyword-value pairs. The SELECTOR of the message is the joining-together of all the keywords into one symbol, which is the name of the message. For example,

Slate> 5 min: 4 max: 7. 
7
is a keyword message-send named min:max: which has 3 arguments: 5, 4, and 7. However,

Slate> 5 min: (4 max: 7). 
5
is a different kind of expression. Two keyword message-sends are made, the first being max: sent to 4 and 7, and min: sent to 5 and the first result. Note however, that even though the first expression evaluates to the same value as:

Slate> (5 min: 4) max: 7. 
7
that this is still a distinct expression from the first one, with two message-sends of one keyword each instead of one send with two keywords. Actually, this expresses the definition of min:max:, although this is perhaps one of the most trivial uses of method names with multiple keywords.

Keywords have the lowest precedence of message-sends, so arguments may be the results of unary or binary sends without explicit grouping required. For example, the first expression here is equivalent to the latter implicitly:

Slate> 5 + 4 min: 7 factorial max: 8. 
9 
Slate> (5 + 4) min: (7 factorial) max: 8. 
9

2.2.4 Expression Sequences

Expressions occur between stop-marks, which are periods. At the top-level, expressions aren't evaluated until a full stop is entered. The stop mark also means that expression results aren't directly carried forward as an argument to the following expression; side-effects must be used to keep the results. More specifically, each expression in the sequence must be evaluated in order, and one expression's side-effects must effectively occur before the next expression begins executing and before any of its side-effects occur.

Slate provides for a bare expression sequence syntax that can be embedded within any grouping parentheses, as follows:

Slate> 3 + 4. 
7

Slate> (7 factorial. 5 
 negated) min: 6. 
-5

The parentheses are used just as normal grouping, and notably, the 5 negated expression wraps over a line, but still evaluates that way. (We do not consider this expression good style, but it illustrates the nature of the language.) If the parentheses are empty, or the last statement in a sequence is followed by a period before ending the sequence, an ``empty expression'' value is returned, which is Nil by convention.

2.2.5 Implicit-context Sends

Within methods, blocks, and even at the top-level, some expressions may take the surrounding context as the first argument. There is a precedence for the determination of which object becomes the first argument, which is entirely based on lexical scoping. So, within a block, an implicit send will take the block's run-time context as argument, and then at lesser precedences will be the next outer contexts in sequence, up to the top-level and what it inherits from.

Specifically, any non-literal expression following a statement-separator or starting an expression within parentheses or other grouping is an implicit-context send.

There are some very common uses of implicit-context sends. In particular, accessing and modifying local variables of a block or method is accomplished entirely this way, as well as returns. For example,

[| :i j k |  
 j: i factorial.  
 k: (j raisedTo: 4).  
 j < k ifTrue: [| m |  
   j: j - i. m: j.  (m raisedTo: 3)].  
 k: k - 4.  
 k 
].
is a block which, when invoked, takes one argument and has another two to manipulate. Notice that the local slot j is available within the enclosed block that also has a further slot m. Local blocks may also override the slots of their outer contexts with their input and local slots. In this case, the identifiers j and j:, for example, are automatically-generated accessing and update methods on the context. Because j: is a keyword message, if the assigned value is a keyword message-send result, it must be enclosed in parentheses to distinguish the keyword pattern. The  (m raisedTo: 3) message causes the context to exit prematurely, returning as its value the result of the right-hand argument. All methods have this method defined on them, and it will return out to the nearest named block or to the top-level.

In some cases, it may be necessary to manipulate the context in particular ways. In that case, it can be directly addressed with a loopback slot named thisContext, which refers to the current activation. The essence of this concept is that within a block, x: 4. is equivalent to thisContext x: 4.1


next up previous contents
Next: 2.3 Methods Up: 2 Language Reference Previous: 2.1 Objects   Contents
The Slate Project 2004-01-04