Skip to content

07. Container Types

Tom Dodd edited this page Dec 13, 2023 · 20 revisions

Similar to Python, DSSL has some useful container types: Range, List, Set and Dict, built into the language alongside the primitive types. All of them are constructed from the elements on the stack between their associated opening and closing brackets: ( and ) for ranges, [ and ] for lists, (| and |) for sets, and [| and |] for dictionaries. The bracket elements are discarded when the container is made. For example, the following code will push a list containing three elements to the stack:

[ 2 "pi" 6.283 ]

Sets are constructed in an intuitively similar manner to the list above. Ranges are constructed using one to three arguments as in Python, and can be used in a similar way. A foreach loop, which iterates through a container and executes a block after the container pushes its next element to the stack, could be used to rewrite the example using isEven from before:

( 1 11 ) {
    /n exch def
    n " is " ~ n isEven { "even" } { "odd" } ifelse ~
    println
} foreach

Instead of manually incrementing a counter and conditionally breaking the loop, we instead use the def keyword to store the value of the most recently yielded element locally. The exch keyword, which swaps the two top elements on the stack, is needed to put the label before the value.

When a dictionary is constructed, each two elements between the brackets form a key-value pair. The following code creates a dictionary variable intWords with two entries, and adds one more with the .put method:

/intWords [| 1 "one" 2 "two" |] def
3 "three" intWords .put

When iterating over a dictionary, each key-value pair is pushed as a list of two elements. In order to keep the access of the elements in this pair succinct, we can use a destructuring definition:

intWords {
    [ /k /v ] exch def      # Define separate variables for key and value
    k " -> " ~ v ~ println  # Use variable identifiers as usual
} foreach

Destructuring can also be used for assignment, requiring iterable elements for both the labels and values. There must be at least as many values as there are labels, and if there are more values than labels, the additional ones are discarded.

Sets and dictionaries use hash sets and hash maps internally, and will use the .hash method and == operator of elements to enact the uniqueness of their entries and keys, respectively.

All built-in methods of the container types are listed here. Some methods use an iterable element as an argument, which can be any element with a .iter method.

Like the primitive types, the container types also have a simple constructor which pops a value of their respective type and pushes it back to the stack.

Clone this wiki locally