next up previous contents index
Next: 3.6 Symbols Up: 3 The Slate World Previous: 3.4 Traits   Contents   Index

Subsections

3.5 Blocks, Booleans, and Control-Flow

3.5.1 Boolean Logic

Slate's evaluator primitively provides the objects True and False, which are clones of Boolean, and delegate to Boolean traits. Logical methods are defined on these in a very minimalistic way. Table cap:Basic-Logical-Operators shows the non-lazy logical methods and their meanings.


Table 2: Basic Logical Operators
Description Selector
AND/Conjunction /\
OR/Disjunction \/
NOT/Negation not
EQV/Equivalence eqv:
XOR/Exclusive-OR xor:


3.5.2 Basic Conditional Evaluation

Logical methods are provided which take a block as their second argument (/\, \/, and:, or:, xor:, eqv:). By accepting a block as the second argument, they can and do provide conditional evaluation of the second argument only in the case that the first does not decide the total result automatically7. Blocks that evaluate logical expressions can be used lazily in these logical expressions. For example,

(x < 3) /\ [y > 7].
only evaluates the right-hand block argument if the first argument turns out to be True.

(x < 3) \/ [y > 7].
only evaluates the right-hand block argument if the first argument turns out to be False.

In general, the basic of booleans to switch between code alternatives is to use ifTrue:, ifFalse:, and ifTrue:ifFalse: for the various combinations of binary branches. For example,

x isNegative ifTrue: [x: x negated].
ensures that x is positive by optionally executing code to assign a positive form if it's not. Of course if only the result is desired, instead of just the side-effect, the entire expression's result will be the result of the executed block, so that it can be embedded in further expressions.

Conditional evaluation can also be driven by whether or not a slot has been initialized, or whether a method returns Nil. There are a few options for conditionalizing on Nil:

expr ifNil: block
and expr ifNotNil: block execute their blocks based on whether the expression evaluates to Nil, and returns the result.
expr ifNil: nilBlock ifNotNil: otherBlock
provides both options in one expression.
expr ifNotNilDo: block
applies the block to the expression's result if it turns out to be non-Nil, so the block given must accept one argument. ifNil:ifNotNilDo: is also provided for completeness.
There is also a ``case-switch'' style idiom:

expr caseOf: cases otherwise: defaultBlock
takes the result of the first argument and the cases array of Associations (made with ->) from objects to blocks and executes the first block associated with a value equal to the expression. If none match, the last argument is executed; the otherwise: clause may be omitted, to just do / return nothing.


3.5.3 Early Returns

Control-flow within methods can be skipped with a return value using the ^ message to the context. ^ takes its second argument and exits the nearest surrounding lexical scope that is a named method (and not an anonymous code block) with that value. This message is a real binary message with no special precedence, so disambiguation is often needed. For example,

^ 4

^ n factorial

return the expressions on the left as a whole, but

^ 3 + 4

^ (3 + 4)

^ set collect: [| :each | each name]

^ (set collect: [| :each | each name])

represent expression variations where a lack of disambiguation results in returning an unintended answer.


3.5.4 Looping

Slate includes various idioms for constructing basic loops. These are all built from ordinary methods which work with code blocks, and any ordinary code may define similar idioms rather quickly.

loop
executes the block repeatedly, indefinitely8.
n timesRepeat: block
executes the block n times.
condition whileTrue: block
and condition whileFalse: block execute their blocks repeatedly, checking the condition before each iteration (implying that the body block will not be executed if the condition is initially false).
whileTrue
and whileFalse execute their blocks repeatedly, checking the return value before repeating iterations (so that they will always execute at least one time).
a upTo: b do: block
and b downTo: a do: block executes the block with each number in turn from a to b, inclusive.
upTo:by:do:
and downTo:by:do: executes the block with each number in turn in the inclusive range, with the given stepping increment.
a below: b do: block
and b above: a do: block act identically to the previous method except that they stop just before the last value. This assists in iterating over array ranges, where the 0-based indexing makes a difference in range addresses by one, avoiding excessive use of size - 1 calls.
below:by:do:
and above:by:do: vary on the previous methods with the given stepping increment.

3.5.5 Method Operations

Slate provides some powerful methods for operating on Method (block) objects themselves. The answers of these operations are also fully-fledged Method objects which respond to all of the normal queries and are useful anywhere that a Method is accepted.

**
composes two Methods in a functional manner, so that $(F\circ G)(x)=F(G(x))$; basically the result of applying the first to the result of the second (which in turn consumes the input). This operation is associative, so grouping of continued applications should not be a concern. This semantics assumes that the inner/right function $G$ may take any number of arguments, and that $F$ takes 1. If both of these are false, then there is an extended form of the semantics where the arity of $F$ is used to group the results of applying $G$ to each element in the argument array. The groups are then passed as a whole to one invocation of $F$.
`er
takes a literal Symbol taken as a message selector and expands into an appropriate Method which takes an appropriate number of arguments for the selector and sends the selector to those arguments, answering the result. E.g. #+`er expands into [| :x :y | x + y] and #name`er expands into [| :x | x name].
converse
takes a Method and answers a new Method with the same body but with input argument order reversed.
`commutatively
takes a literal MethodDefinition and defines it with two signatures, one reversed from the original definition, with the same body.


next up previous contents index
Next: 3.6 Symbols Up: 3 The Slate World Previous: 3.4 Traits   Contents   Index
Brian Rice 2005-11-21