Skip to the main content of this page.
The sable mammal, Martes zibellina
SABLE Programming Language

Identifiers

To support namespaces, nested classes, and field access, SABLE supports dotted identifiers. Parameterized type references are also identifiers. A leading dot can be used to indicate a global reference, bypassing locally scoped items. These are all valid identifiers:

index
My.name
UINT32.MaxValue
System.Collections.Generic.DICTIONARY[STRING,INT32]
.System.Collections.Generic.DICTIONARY[STRING,INT32]
DICTIONARY [STRING, System.IO.FILE_STREAM].VALUE_COLLECTION

However, an instance field can be directly accessed using dot notation only by the declaring class and its subclasses. "Foreign" classes must use messages; unlike Smalltalk however, the compiler generates getters and setters for instance fields if you don't, so you don't have to. They access the field directly.

Predefined Identifiers

SABLE has no reserved words1. None! Instead, the compiler predefines the following identifiers. Unless otherwise specified, an identifier is defined in all contexts.

Me, My, MyselfDefined in instance methods and constructors, these refer to the message receiver or the object being constructed. They all alias the same object; this allows expressions to read in a natural fashion, e.g. [My originalValue == Me then: [^Myself]]. By convention, use Myself in self-constructor messages and as a return value in {MyType}-returning messages, My as the receiver of non-Boolean functional messages and for field access, Me for all other uses.
BaseDefined in instance methods and constructors written to CIL (i.e. not in macros), refers to the same object as Me but with special meaning. This is used as a message receiver to invoke methods as defined in the base type, bypassing any overrides.
FalseBoolean false literal. Converts to a number with value 0.
TrueBoolean true literal. Converts to a number with value 1.
NilA literal assignable to any nilable type, represents the no-value value.
VoidNot a value, this allows exiting from methods which don't return a value using [^Void].
ResultDefined in methods returning a value, represents the value being returned. Used only in >#ensure:as: postcondition assertions and in iterator methods.
SABLEDefined in FileIns to control which constructs are being read.
THIS_CLASSWithin a class or method definition, refers to the currently executing type from the perspective of the current class. (See below for details.) Within a FileIn, refers to the last class declared for adding methods into it.
MyTypeDefined only in methods, refers to the currently executing type from the perspective of the message receiver. (See below for details.)
DefaultDefined as a constant in all parameter types, #Default represents the type's default (Nil, False, or 0) value.

THIS_CLASS and MyType

What's the difference between THIS_CLASS and MyType? THIS_CLASS is fixed like a class, never referring to a subtype; it's a substitute for writing the current class name with its formal generic parameters (if any). It's a notational convenience only.

MyType is semantically very different and even more useful. It varies like a parameter, changing to match the receiver of any message. Earlier we looked at the method header for >#to:by:do: and saw how it matched its block argument type to the receiver type. A similar approach is used to define the numeric operators. E.g.

+: other {MyType}  ^{MyType}.
    {~ primitive: #+:}

Such methods are defined in a single interface which is implemented by all the number classes. Using {MyType}, the operator argument and return types are determined by the receiver's type.

Also, OBJECT defines this instance method to test object equality:

=: other {MyType}  ^{BOOLEAN}.
    {~ primitive: #=:; replacedIn: #()}
    "Are these object's values equal?
     If I'm a primitive type, compare directly in CIL.
     If I'm a NILABLE reference type, use OBJECT>~>#areEqual:and: to account for Nil.
     If I'm a NULLABLE value type, use NULLABLE>~>#areEqual:and: to account for [Me hasValue not].
     Otherwise, use the >#equals: method defined for me."

This ensures statically at compile time that the argument's type is compatible with the receiver's, preventing from the start impossible pairings such as: [aString = anException].

A final example to illustrate the difference: Class ENUM, the base of all enumerated types, implements this static macro:

ENUM staticMethods public in: 'ENUM macros'names  ^{ARRAY[STRING]}.
    {~ macro inherited}
    "The names of all constants defined by this enumerated type."
     ^THIS_CLASS getNames: MyType

THIS_CLASS refers to ENUM, invoking its static method >#getNames:. However, the argument depends on the receiver. [CONSOLE_COLOR names] is equivalent to [ENUM getNames: CONSOLE_COLOR]. Notice that MyType can be useful in static methods, too, and how it helps the macro make client code more succinct and clear. (To permit this kind of usage, static macros can be inherited.)


1 A reserved word is a name with special meaning in the language grammar.