Nil
thisContext
lobby
True
False
Unlike common object-oriented languages, Slate does not have a designated "self" or "this" or "super" object pseudo-variable; instead, objects have whatever names within their methods that are bound in the definition. This is a consequence of multi-method dispatch semantics.
Object identifiers start with a letter and end in any character but a reserved character. This allows a greater freedom for object naming, but means that programmers should use whitespace properly. This may change in the future. They are also case-sensitive.
To be safe, follow this pattern:
letter ( letter | digit )*
Unlike some Smalltalks, underscores are not reserved.
Also, as a general convention, capitalization is used relatively sparingly, usually for permanent objects that have "proper" names.
"This is a meaningless comment. It spans a couple of lines."
$x "A character is any character (even unprintable ones), preceded by a dollar sign" $3 "Don't be shy about characters that are digits" $< "or symbols" $$ "or even the dollar sign"
Some involve escapes:
$\e "Escape" $\n "NewLine" $\r "CarriageReturn" $\t "Tab" $\b "Backspace" $\0 "Null" $\s "Space"
This will likely evolve into something more expansive.
'a string comprises any sequence of characters, surrounded by single quotes' 'strings can include the "comment delimiting" character' 'and strings can include embedded single quote characters by escaping\' them' 'strings can contain embedded newline characters' 'and escaped \ncharacters' '' "and don't forget the empty string"
Strings are arrays of characters, and are not resizable. Arrays in Slate are indexed from 0, not 1 as in Smalltalk.
#'A string preceded by a hash sign is a Symbol' #orAnyIdentifierPrefixedWithAHashSign #orAnIdentifierEndingWithAColon: #or:several:identifiers:each:ending:with:a:colon: #here's:a:symbol:that:isn't:a:keyword #- "A symbol can also be a hash followed by '-' or any special character" #+< "or a hash followed by any pair of special characters"
Any identifier, also, is a symbol when prefixed by #
. Escapes via \
are also allowed.
'test one two three'
, but every symbol having the characters #'test one two three'
is the same instance. This "unique instance" property means that Symbols can be efficiently compared, because equality (=
) is the same as identity (==
).#a:keyword:selector:
) are often referred to as keyword selectors, for reasons that will be made clear later.#*
or #++
) are often referred to as binary selectors.+/*\~<=>%|&?!;^_
@
and `
are reserved in Slate, but not ;
or ^
or _
.#--
is not a symbol (or a binary selector). On the other hand, #'--'
is a symbol (but not a binary selector).{
and ends with }
. They may contain nested arrays, given by {} braces, not needing the #
prefix at any point as Smalltalk uses. Expressions within are evaluated, and their return values are stored as the elements. The element-separator is a period (".").
Arrays are indexed from 0
to below their size
.
Prefixing array or block literals with the #
character will cause it to be evaluated at compile-time, and have its result inserted in place within the surrounding expression. Arrays return themselves, and blocks return their last expression or a pre-mature explicit return value.
The #
prefix also can generate Smalltalk-style #()
literal arrays, in which every expression within is just read as its symbolic name, and nothing is evaluated. Whitespace is used as the element separator.
All of these literal expression types can be nested within each other without the #
prefix since it all has been forced to compile-time already.
foo addSlot: #x.
generates methods #x
and #x:
on foo
.
Local and input variables in blocks and methods (dispatched blocks) use this very same mechanism.
Assignments are expressions and return the assigned value.
In later Slate versions, there will be hooks to provide other accessor and mutator methods on slot creation.
Because keyword syntax is used, there is a precedence issue if you cascade assignments:
y: (x: (z w: 4)).
These are identical to those in Smalltalk and Self, only extended somewhat since Slate reserves different characters.
theta sin quantity sqrt nameString size 1.5 tan rounded as: String "same result as (((1.5 tan) rounded) as: String)"
#asString
to the result of sending #rounded
to the result of sending #tan
to 1.5
3 + 4 " ==> 7 " 3 + 4 * 5 " ==> 35 (not 23) " 3 + 4 factorial " ==> 27 (not 5040) " total - 1 total <= max "true if total is less than or equal to max" (4 / 3) * 3 = 4 "==> true equality is just a binary message, and Fractions are exact" (3 / 4) == ( 3 / 4) "==> false two equal Fractions, but not the same object"
3
the message comprising the selector #+
with the argument 4
.12 between: 8 and: 15 " ==> true " {$t. $e. $s. $t} at: 2 " ==> $s " array at: index put: value "==> answers value, after storing value in array at index" array at: index factorial put: value "same, but this time stores at index factorial" 1 to: 3 do: aBlock "This sends #to:do: (with two parameters) to integer 1" (1 to: 3) do: aBlock "This sends #do: (with one parameter) to the Interval given by evaluating '1 to: 3'"
expressionSequence ::= expression (. expression)* (.)opt
box origin: (Point x: 20 y: 30) corner: (Point x: 60 y: 90). box containsPoint: (Point x: 40 y: 50)
(NOTE to Smalltalk and Self users: there is not yet a binary selector for Point creation. Also, there are no cascaded message-sends since their is no preferred "receiver" argument).
Blocks, actually instances of the class Method. They are used all the time to build control structures. Blocks are created using the [ ] syntax around a sequence of expressions.
[expressionSequence] "block without arguments" [| (: identifier)+ | expressionSequence ] "block with arguments" [| (: identifier)+ identifier+ | expressionSequence ] "block with arguments and local variables"Smalltalkers should note that an extra vertical bar precedes declaration of local and input slots, and no vertical bars are required between inputs and locals.
[ 1. 2. 3 ] "a block which, when evaluated, will answer the value 3" [ object doWithSideEffects. test] "a block which, when evaluated, will send #doWithSideEffects to object, and answer the object test" [| :param | param doSomething ] "a block which, when evaluated with a parameter, will answer the result of sending #doSomething to the parameter."
[ 1. 2. 3 ] value ==> 3
block value
block value: arg
block values: anArray
#value
, sent to a block, causes the block to be executed and answers the result. The block must require zero arguments.#value: arg
, causes the block to be executed. The block must require exactly one argument; the corresponding parameter is initialized to arg
.#value:value:
and #value:value:value:
. If you have a block with more than three parameters, you must use #values:
.thisContext
refers to your activation rather than how currentMethod
obtains the block or method itself.
^ foo
Sends the ^
message to the context, causing it to exit to the next-outermost named method, returning foo as its value. Since this is a binary selector instead of reserved punctuation as in Smalltalk, returning of binary and keyword selector expressions must have its precedence adjusted, e.g.:
^ 3 + 4 ==> 3 ^ (3 + 4) ==> 7 ^ 3 bitAnd: 4 ==> 3 ^ (3 bitAnd: 4) ==> 0
resend
Other types of resends are defined upon Symbols.(Refer to the manual for these and their behavior.)
_@True ifTrue: block ifFalse: _ [block value]. _@False ifTrue: _ ifFalse: block [block value].
Here we have two methods with the same name.
We have appropriated the use of the @ character to note when an argument is significant to dispatch. The expression following @
in this context is where the method should be placed. Keep in mind that this has nothing to do with type declaration: objects are just as flexible as in Self, and this just means that the method is defined upon that object as that particular argument position for use in method dispatch.
For input arguments, you can see the use of both _
and a regular variable name. The underscore just tells the parser that the argument at that position can be ignored, because we're not going to use it's value - we're merely dispatching upon it. Why name something that doesn't have a use?
At the end, we see code enclosed in brackets. That's the method code itself. Every method uses fully general block syntax and semantics, which means it can take additional input variables, and its temporaries are just block temporaries.
For the purists, we should explain the special syntax above in terms of its method-call basis using the following translation of a (silly) method definition:
x@(Integer traits) + y@(Float traits) [ (x as: Float) + y ]. [| :x :y | (x as: Float) + y] asMethod: #+ on: {Integer traits. Float traits}.
These are exactly equivalent. Most of the syntax here is Smalltalk-compatible, with a few exceptions:
There's more, which needs another example method to illustrate.
oc@(OrderedCollection traits) copyFrom: start to: end [| newOC | end < start ifTrue: [^ oc newEmpty]. newOC: (oc traits newSize: end + 1 - start). start to: end do: [| :index | newOC addLast: (oc at: index)]. newOC ].
Here's a method translated from Squeak which provides good examples:
^
returns is for early returns. ^ oc newEmpty
in the above example exits all the blocks that enclose it up to the last method-call. One thing that's not obvious is that ^
is actually a binary message send to the current method activation and the expression to return; like in Self, messages can be sent with an implicit first argument - the current method activation. So if you return a keyword expression, it has to be thus: ^ (oc newSize: 20)
in order to evaluate things in the proper order.