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 expreesion, 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.)

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 2003-07-29