Tutorial
Welcome to the Slate tutorial. Lets start by starting slate with an image:
$ ./slate -i slate.image
That gives us a prompt:
slate-1>
at the prompt we can type code to be evaluated:
slate-1> 2 + 2. 4
Slate binary messages must be separated by spaces. There are three types of messages (from most precedence to least):
- Unary (2 factorial)
- Binary (2 + 2)
- Regular messages (2 min: 5)
If integers are too large to be stored in a machine word, they are automatically converted to big integers:
slate-2> 100 factorial. 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
You can use parenthesis to help with precedence:
slate-3> (2 min: 5) < 3 ifTrue: [False] ifFalse: [True]. False
The root namespace in slate is called the lobby. Everything in slate is an object. Objects have slots in them. We can ask an object what slots it has:
slate-4> lobby
lobby
slate-5> lobby slotNames.
{#VM. #Types. #C. #globals. #systems. #Mixins. #prototypes}
Most slots have accessors built in so we don’t have to manually do it. These are the same:
slate-6> lobby atSlotNamed: #Mixins. (Mixin. CollectionTypeMixin. StructuredPrinterMixin. PrettyPrinterMixin. NumericMixin) slate-7> lobby Mixins. (Mixin. CollectionTypeMixin. StructuredPrinterMixin. PrettyPrinterMixin. NumericMixin)
By default, objects in slate are initialized to Nil when they are created. Here are ways to define objects:
slate-8> lobby addSlot: #x
Defining accessor 'x' on: NoRole
Defining accessor 'x:' on: NoRole, NoRole
Nil
slate-9> lobby addSlot: #y valued: 3.
Defining accessor 'y' on: NoRole
Defining accessor 'y:' on: NoRole, NoRole
3
slate-10> lobby define: #z.
Defining accessor 'z' on: NoRole
Defining accessor 'printName' on: 'z traitsWindow'
Defining accessor 'printName' on: 'z traits'
("z traitsWindow")
Adding a slot as you see above just adds a variable. Define creates a new object in the same way that you would create a new class in other programming languages.
By default, #define: creates objects that inherit from Cloneable (a base object class that provides allows cloning/copying of objects).
Define has a lot of optional arguments which use the ampersand syntax. Lets create a new object with two slots:
slate-11> lobby define: #ArithmeticOp &parents: {Cloneable} &slots: {#x. #y}.
Defining accessor 'ArithmeticOp' on: NoRole
Defining accessor 'printName' on: 'ArithmeticOp traitsWindow'
Defining accessor 'printName' on: 'ArithmeticOp traits'
Defining accessor 'x' on: NoRole
Defining accessor 'x:' on: NoRole, NoRole
Defining accessor 'y' on: NoRole
Defining accessor 'y:' on: NoRole, NoRole
("ArithmeticOp traitsWindow" y: Nil. x: Nil)
The brace syntax lets you create arrays. The elements in them are evaluated like commands and they are separated by periods like commands:
Brackets create anonymous functions:
slate-12> {1. 2. 3. 4. 5} collect: [|:x| x + 1].
{2. 3. 4. 5. 6}
Backquotes represent macros that change the syntax. This creates a unary block calling #isOdd on the argument to it:
slate-13> 5 isOdd.
True
slate-14> {1. 2. 3. 4. 5} select: #isOdd `er.
{1. 3. 5}
You can chain things together and inject arguments into blocks:
slate-15> ({3. 2. 7} collect: #+ `er <- 3) sort.
GC Freed 3828 words and coalesced 168 times
GC tenured 1034 objects (23422 words)
{"SortedArray traitsWindow" 5. 6. 10}
The above spit out a GC message. It’s sort of an indicator on how fast your eating up memory. Another useful macro is the macro to send a lot of messages to one object:
slate-16> [ lobby `>> [addSlot: #a. addSlot: #b. ] ] method sourceTree. [| _0 | lobby `>> [ _0 addSlot: #a. _0 addSlot: #b. ] ]
We can also define methods on objects fairly easily:
slate-17> a1@(ArithmeticOp traits) add [a1 x + a1 y]. Defining function 'add' on: 'ArithmeticOp traits' [add] slate-18> ArithmeticOp new `>> [x: 1. y: 2. add]. 3
What if we screw up?
slate-19> ArithmeticOp new `>> [x: 1. y: False. add].
We are entering the debugger...
Defining function 'frame' on: NoRole
Defining function 'frame:' on: NoRole, NoRole
Defining function 'arg:' on: NoRole, NoRole
Defining function 'arg:put:' on: NoRole, NoRole, NoRole
Defining function 'backtrace' on: NoRole
Defining function 'bt' on: NoRole
Defining function 'restarts' on: NoRole
Defining function 'restart:' on: NoRole, NoRole
Defining function ':' on: NoRole, NoRole
Defining function 'help' on: NoRole
<0> [defaultHandler]
<1> [tryHandlers]
<2> [signal]
<3> [notFoundOn: &optionals:]
<4> [add]
<5> [(arity: 0)]
<6> [do]
<7> [evaluateIn: &optionals:]
<8> [evaluateIn: &optionals:]
<9> [(arity: 0)]
<10> [on:do:]
<11> [(arity: 0)]
<12> [handlingCases:]
<13> [interpretHook:]
<14> [(arity: 0)]
<15> [enter]
<16> [start &resource:]
<17> [start]
[snip]
The following condition was signaled:
The method #'+' was not found for the following arguments:
{1. False}
The following restarts are available:
restart: 0 Abort evaluation of expression
restart: 1 Quit Slate
Enter 'help.' for instructions.
slate-debug[0..1]>
The easiest way to get out of this is to type “: 0.” and press enter. Debugging will be covered in more advanced tutorials.
The important commands are “bt” to get a backtrace and “frame: 4″ (or some other frame number) to display information about that call frame.
slate-debug-[0..1]> : 0. slate-20>