how 2SWAP works

I’m learning Forth. So far, so good. Even if I don’t end up using it for much, maybe it will make me a better dc user.

Anyway, I’m using the much-praised book “Starting Forth” by Leo Brodie, which I picked up used a few months ago. For the most part, I like it, but I its explanation of the “double” stack manipulators is terrible.

Earlier in the book, you’ve learned about these operators:

DUP   - duplicate the top number on the stack
SWAP  - swap the top 2 number on the stack
OVER  - copy the 2nd number down the stack to the top
        (i.e., given (a b c) you end up with (a b c b))
DROP  - discard the top number on the stack

Later, variants are described:

2DUP   - duplicate the top 2 pairs of numbers on the stack
2SWAP  - swap the top pair of numbers on the stack
2OVER  - copy the 2nd pair of numbers down the stack to the top
2DROP  - discard the top pair of numbers on the stack

This would be all be pretty clear with examples, but instead we get the “stack notation,” which is something like a function signature. For example:

SWAP    ( n1 n2 -- n2 n1 )
2SWAP   ( d1 d2 -- d2 d1 )

This is not at all what I would expect. Does d mean “pair of numbers” or something? Well:

The prefix "2" indicates that these stack manipulation operators handle
numbers in pairs. The letter "d" in the stack effects column stands for
"double." "Double" has a special significance that we will discuss when we
talk about "n" and "u."

Depending on how much C you know, you are either more or less confused by this explanation. If you’re only learning to program from this book (which is supposed to be possible), you are probably totally lost. n, we have been told, means single-length numbers, and d is for double-length numbers. The 2SWAP word swaps two pairs of numbers – by which they implicitly mean single-length numbers – but it can also swap two (non-pairs of) double-length numbers. The printed book explains in a footnote that single-length numbers range from -32K to 32K and the website has replaced that range with -2e9 to 2e9.

To understand what’s really going on, if you don’t know how numeric representation works, you need some examples, and probably a quick explanation of how an integer and double differ and are stored on the stack. Instead, you get this line:

The "2"-manipulators listed above are so straightforward, we won't even
bore you with examples.

Wow. That lack of examples cost me plenty of time. (The Gforth Manual’s tutorial isn’t much better.) The closest to an example we get is this exercise:

Exercise 2-1

Q: What’s the difference between DUP DUP and 2DUP?

A:
DUP DUP: (1 2 – 1 2 2 2)
2DUP: (1 2 – 1 2 1 2)

So, how does 2SWAP work? Well, your stack is a sequence of memory, divided up into units. One unit is big enough to store a single-width number. SWAP swaps the top two units, which will reverse the position of two single-width numbers, or mangle anything else. 2SWAP does the same thing, but acts on regions twice as big. One of the book’s many cartoons could have illustrated this nicely: two pairs of single-width numbers would be reversed, or two double-width numbers. Again, anything else would be likely to be mangled.

I think the real problem is avoiding discussing memory or representation in memory. Without understanding these concepts, Forth does not seem like a language one can learn easily. It’s the same problem you see with people learning Git who haven’t learned how commits form graphs. If that isn’t explained early, everything else is a mystery.

Now, back to learning Forth.

Written on July 22, 2011
forth   programming