Go to the first, previous, next, last section, table of contents.


Blocks

Let me introduce you to one final, fairly general and widely used MUF facility before letting you go.

Evaluation stacks are very efficient ways of allocating and freeing small amounts of temporary storage, but most languages use them very clumsily, a problem which often becomes evident when dealing with functions which accept or return a variable number of arguments.

Traditional Forth implementations (and tinyMuck MUF) are little better, using a clumsy and error-prone convention of an integer count pushed on top of the argument vector.

Muq MUF systematizes this by introducing the concept of stack blocks and a variety of operations upon them.

A stack block may be created by enclosing some number of arguments between [ and |. The | is syntactic sugar for a count which tracks the size of the stackblock and allows operations to be performed upon the block quite efficiently:

root:
[ "this" "is" "a" "block" "of" "words" |
root: [ "this" "is" "a" "block" "of" "words" |
|sort
root: [ "a" "block" "is" "of" "this" "words" |
|mix
root: [ "block" "this" "is" "of" "words" "a" |
|pop
root: [ "block" "this" "is" "of" "words" | "a"
--> _tmp
root: [ "block" "this" "is" "of" "words" |
_tmp
root: [ "block" "this" "is" "of" "words" | "a"
|push
root: [ "block" "this" "is" "of" "words" "a" |
|shift
root: [ "this" "is" "of" "words" "a" | "block"
|unshift
root: [ "block" "this" "is" "of" "words" "a" |
]vec
root: #<vec>
vals[
root: [ "block" "this" "is" "of" "words" "a" |
|dup[
root: [ "block" "this" "is" "of" "words" "a" | [ "block" "this" "is" "of" "words" "a" |
]|join
root: [ "block" "this" "is" "of" "words" "a" "block" "this" "is" "of" "words" "a" |
|sort
root: [ "a" "a" "block" "block" "is" "is" "of" "of" "this" "this" "words" "words" |
|uniq
root: [ "a" "block" "is" "of" "this" "words" |
|length
root: [ "a" "block" "is" "of" "this" "words" | 6
pop
root: [ "a" "block" "is" "of" "this" "words" |
|dup[
root: [ "a" "block" "is" "of" "this" "words" | [ "a" "block" "is" "of" "this" "words" |
]pop
root: [ "a" "block" "is" "of" "this" "words" |
1 |rotate
root: [ "block" "is" "of" "this" "words" "a" |
-1 |rotate
root: [ "a" "block" "is" "of" "this" "words" |
3 |rotate
root: [ "of" "this" "words" "a" "block" "is" |
]words
root: "of this words a block is"
words[
root: [ "of" "this" "words" "a" "block" "is" |
]join
root: "ofthiswordsablockis"
"i" chopString[
root: [ "ofth" "swordsablock" "s" |
]words
root: "ofth swordsablock s"
vals[
root: [ 'o' 'f' 't' 'h' ' ' 's' 'w' 'o' 'r' 'd' 's' 'a' 'b' 'l' 'o' 'c' 'k' ' ' 's' |
|upcase
root: [ 'O' 'F' 'T' 'H' ' ' 'S' 'W' 'O' 'R' 'D' 'S' 'A' 'B' 'L' 'O' 'C' 'K' ' ' 'S' |
|downcase
root: [ 'o' 'f' 't' 'h' ' ' 's' 'w' 'o' 'r' 'd' 's' 'a' 'b' 'l' 'o' 'c' 'k' ' ' 's' |
|sort
root: [ ' ' ' ' 'a' 'b' 'c' 'd' 'f' 'h' 'k' 'l' 'o' 'o' 'o' 'r' 's' 's' 's' 't' 'w' |
|uniq
root: [ ' ' 'a' 'b' 'c' 'd' 'f' 'h' 'k' 'l' 'o' 'r' 's' 't' 'w' |
|charInt
root: [ 32 97 98 99 100 102 104 107 108 111 114 115 116 119 |
|sum
root: [ 32 97 98 99 100 102 104 107 108 111 114 115 116 119 | 1422
pop
root: [ 32 97 98 99 100 102 104 107 108 111 114 115 116 119 |
|intChar
root: [ ' ' 'a' 'b' 'c' 'd' 'f' 'h' 'k' 'l' 'o' 'r' 's' 't' 'w' |
|for v do{ v , } "\n" ,
 abcdfhklorstw
root: [ ' ' 'a' 'b' 'c' 'd' 'f' 'h' 'k' 'l' 'o' 'r' 's' 't' 'w' |

The general convention is that a function with a name ending with [ creates a stackblock (think of Unix shell syntax '<' for opening a pipeline), a function beginning with | operates on a pre-existing stackblock (again, think of Unix shell pipe notation) and a function beginning with ] consumes a stackblock (like Unix shell > for terminating a pipeline).

Obviously, every [ in an expression should have a balancing ] somewhere.

See the block section of the MUF reference manual for a fuller listing of the block functions.

MUF functions may actually accept and return multiple stackblocks, as well as multiple individual arguments. The syntax for declaring this to the compiler uses [] in place of the $ used for declaring a scalar argument or result:

root:
: ]]pop { [] [] -> }  ]pop ]pop ;
root:
[ "abc" | [ "def" |
root: [ "abc" | [ "def" |
]]pop
root: 

Block arguments must always precede (be below) scalar arguments, both call and return.

Using stack blocks is a great way to avoid grinding the garbage collector heavily by creating scads of small objects as intermediate values in an expression. For example, manipulating a stackblock of characters generates no garbage, while doing the equivalent operation with string operators might generate a number of garbage strings. (Note, however, that strings shorter than eight characters also count as zero garbage, since they are stored as immediate stack values rather than being allocated on the heap.)


Go to the first, previous, next, last section, table of contents.