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):

  1. Unary (2 factorial)
  2. Binary (2 + 2)
  3. 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>