Skip to content

11. Classes

Tom Dodd edited this page Dec 11, 2023 · 7 revisions

Alongside the classes associated with the built-in primitive and container types, DSSL adds support for user-defined classes. A class is defined using the class keyword with a label and block element as the first and second arguments, respectively. Once defined, the class's hierarchy becomes a sub-hierarchy of the current scope, much like the hierarchy of imported scripts. For that reason, classes can simply be used to construct namespaces without imports:

/Math {
    /pi 3.14159265358979323846 def
    /e 2.71828182845904523536 def
    
    /factorial {
        /result 1 def
        1 + ( 1 3 2 roll ) {
            /result exch *=
        } foreach
        result
    } macro
} class

"pi + e = " Math .pi Math .e + ~ println
"52! = " 52 Math .factorial ~ println

The new keyword is used to create instances of a class from a class element on the top of the stack, which can be created by using the class's identifier. The following defines two variables a and b as instances of the Pos class and prints their magnitudes using the abs method:

/Pos {
    /__init__ {
        /this exch def
        /this .z exch def
        /this .y exch def
        /this .x exch def
        this
    } macro
    
    /abs {
        /this exch def
        this .x 2 ** this .y 2 ** + this .z 2 ** + 0.5 **
    } macro
    
    /__add__ {
        /this exch def
        /other exch def
        this .x other .x + this .y other .y + this .z other .z + Pos new
    } macro
    
    /__str__ {
        /this exch def
        "[" this .x ~ ", " ~ this .y ~ ", " ~ this .z ~ "]" ~
    } macro
} class

/a 3 4 5 Pos new def
/b 1.41 1.73 2.24 Pos new def

a Pos .abs println  # static access
b .abs println      # instance access

While a's magnitude is obtained by using static access to the macro in the Pos sub-hierarchy, the interpreter knows that b is an instance of Pos and so an instance access is performed, which first pushes b to the stack before executing the Pos .abs macro, resulting in the same outcome.

Members defined with particular names add indirect magic functionality to instances of the class. For example, the constructor __init__ executes directly after the new keyword pushes the new instance to the stack. The constructor of the Pos class pops the top three elements after the new instance and uses them to define the member variables x, y and z. If any instances of a class are created within the class definition itself, they must be created after the constructor has been defined.

Magic definitions can also be used for overloading built-in operators, such as addition with __add__, and defining explicit string casts with __str__. For example, the Pos class defines magic for each of these, and the following code prints a + b = [4.41, 5.73, 7.24];

/c a b + def
"a + b = " c ~ println

All identifiers for members with magic functionality are listed here.

Note that individual instances have their own hierarchies, and so it is possible to define members in them which no other instances will have:

/c .shout { "Hello!" println } macro
c .shout
Clone this wiki locally