Learn: Definitions

Being a concatenative language, min does not really need named parameters or variables: symbols just pop elements off the main stack in order, and that’s normally enough. There is however one small problem with the traditional concatenative paradigm; consider the following program for example:

stack.dup stack.dup "\\.zip$" match? stack.swap fs.size 1000000 > and stack.swap fs.mtime now 3600 - >

This program takes a single string corresponding to a file path and returns true if it’s a .zip file bigger than 1MB that was modified in the last hour. Sure, it is remarkable that no variables are needed for such a program, but it is not very readable: because no variables are used, it is often necessary to make copies of elements and push them to the end of the stack – that’s what the stack.dup and stack.swap are used for.

The good news is that you can use the define operator and the : sigil to define new symbols, and symbols can also be set to fixed values (literals).

Consider the following program:

:filepath filepath "\\.zip$" match? filepath fs.size 1000000 > filepath fs.mtime time.now 3600 - > and and

In this case, the filepath symbol is defined and then used on the following three lines, each of which defines a condition to be evaluated. The last line contains just two and symbols necessary to compare the three conditions.

Lexical scoping and binding

min, like many other programming languages, uses lexical scoping to resolve symbols.

Consider the following program:

4 :a ( a 3 + :a ( a 1 + :a (a stack.dup * :a) dequote ) dequote ) dequote

…What is the value of the symbol a after executing it?

Simple: 4. Every quotation defines its own scope, and in each scope, a new variable called a is defined. In the innermost scope containing the quotation (a stack.dup * :a) the value of a is set to 64, but this value is not propagated to the outer scopes. Note also that the value of a in the innermost scope is first retrieved from the outer scope (8).

If we want to change the value of the original a symbol defined in the outermost scope, we have to use the bind or its shorthand sigil @, so that the program becomes the following:

4 :a ;First definition of the symbol a ( a 3 + @a ;The value of a is updated to 7. ( a 1 + @a ;The value of a is updated to 8 (a stack.dup * @a) dequote ;The value of a is now 64 ) dequote ) dequote

Sealing symbols

Finally, symbols can be sealed to prevent accidental updates or deletions. By default, all symbols defined in the core min modules are sealed, so the following code if run in min shell will result in an error:

5 :quote

…because the symbol quote is already defined in the root scope. However, note that the following code will not return an error:

(5 :quote quote stack.dup *) -> ;returns 25

…because the quote symbol is only defined in the root scope and can therefore be redefined in child scopes.

If you want, you can seal your own symbols so that they may not be redefined using the bind operator or deleted using the delete.

Note

The unseal-symbol operator can be used to effectively un-seal a previously-sealed symbol. Use with caution!

→ Continue to Scopes