Slate descends from the Self programming language, where object-centered development is emphasized. So, instead of instantiating classes to form new objects, pre-existing objects are copied or cloned and modified to produce new ones. Re-use of existing code, data, and behavior is accomplished through delegation between objects: whenever a service is requested of an object which is not defined directly by it, it consults the objects in slots marked for delegation for the same services with the original object as the argument.
Slate, however, takes after Smalltalk in that the syntax distinguishes between objects and block closures (or methods) syntactically. The literal object syntax of Self does not carry forward into Slate.
Slate provides several primitive messages to manage slots:
object addSlot: slotSymbol
object addSlot: name valued: val
object addDelegate: slotSymbol
and object addDelegate: slotSymbol valued: val
Each of the former has a variant which doesn't result in a mutator method being generated for its slot: addImmutableSlot:valued:
and addImmutableDelegate:valued:
.
Root
Oddball
Nil
Derivable
derive
and deriveWith:
, which means they can be readily extended.Cloneable
Method
Blocks in Slate are procedures with input and local argument possibilities that are packaged as separate objects. Blocks are not executed when they are defined; they must be sent messages to be evaluated, and can be re-evaluated later on. When a block is evaluated, a special activation object is created which holds its execution state, and is then discarded after being used.
Blocks also have the property of lexical closure: that is, they "remember" the environment in which they were defined, but can also be returned as values and invoked elsewhere, still recalling implicitly what was present where they were defined.
Methods are procedures that are associated with a number of objects. They have arguments which are their inputs, and dispatchers which are "co-owners" of the method. Arguments in Slate are always named, and occur in a position within the call to a method called a message. The name of a method is called its selector, and in Slate often consists of a number of keyword-style words joined together.
When a method is defined, it must be dispatched to one or more objects for some argument positions. These objects are found and annotated with the method is defined. These annotations are what defines the method's applicability: the system ensures that objects given for argument positions that are dispatched must inherit from those objects.
Because of the importance of roles and annotations in Slate method definitions, method objects are not the sole property of a given dispatch object. Methods stand alone as code blocks.
A message in Slate is a polymorphic procedure call. When a message is sent to a number of objects, the system determines dynamically (by default) what method is invoked in response. The method will have the same name as the message's selector, and will be found by looking into the objects and their inheritances for dispatch associations that match. In Slate, all arguments are consulted to determine what method is called; this is referred to as multiple dispatch in contrast to single dispatch for most common object-oriented languages.
When methods are defined, the annotation made from a dispatched object to the method is called a role: this emphasizes that the object is a representative of those objects which can play a role in that method by being present in that argument position. So a role annotation says: "I and those inheriting from me may show up in this method with that name in that position". Any object may have role annotations, and the roles can be for any position.
The process of determining the appropriate method to invoke for a message-send is the lookup process. This is performed by consulting all of the arguments themselves and the objects that they inherit. A few basic factors are involved in determining the appropriateness of the methods found: