<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>code &amp;mdash; blog dot information dash superhighway dot net</title>
    <link>https://blog.information-superhighway.net/tag:code</link>
    <description></description>
    <pubDate>Sat, 02 May 2026 04:05:21 +0000</pubDate>
    <item>
      <title>A Forth vocabulary for iteration</title>
      <link>https://blog.information-superhighway.net/a-forth-vocabulary-for-iteration</link>
      <description>&lt;![CDATA[I recently wrote a small 16-bit Forth for 8086 PCs running DOS. I built the basic one-liner loop words that can trivially be built with just &#34;branch if zero&#34; and &#34;goto&#34;: begin, while, repeat, until, again. But I held off on implementing do / loop at first.&#xA;&#xA;It didn&#39;t seem like too much of a hardship. In a previous Forth I&#39;d built, I&#39;d implemented do / loop using the return stack, but it was... ugly. The code to implement it was ugly, the code it generated was ugly (and large!), and I didn&#39;t find a lot of places where it was actually much nicer to use than explicit begin-based loops. I was able to implement an 8086 assembler and a Minesweeper game without bothering to build do / loop. I didn&#39;t really miss it, but I had a design percolating in the back of my mind that I wanted to try.&#xA;&#xA;At some point I came across some writing that suggested that Forth had a &#34;loop control stack&#34;. Wouldn&#39;t it be nice if I could implement some kind of loop control stack that worked for all kinds of iteration?&#xA;&#xA;The thing I built has blown me away with how flexible, composable, and useful it&#39;s turned out to be. It&#39;s way more powerful than I was expecting. And the code that leverages it is inevitably much simpler and easier to read. !--more--&#xA;&#xA;The Stacks&#xA;&#xA;I added two loop control stacks - what I call the i-stack, and the next-stack. The i-stack contains the current value(s) being iterated over, and is read from with the i and j words like normal. The next-stack is where the magic happens.&#xA;&#xA;When iterating, the top value of the next-stack is a pointer to a small structure called an iterator. It&#39;s a very simple structure, only two cells. The first cell contains the execution token of a word that will either update the current values on the i-stack and return true, or remove its state from both stacks and return false. The second cell points to a cancellation function, that cleans up whatever state the iterator has kept on the two stacks without iterating further, and returns nothing.&#xA;&#xA;Iterators&#xA;&#xA;I built some simple helpers for creating iterators. It took a few tries to nail down this design, but I&#39;m happy with it now. defiter creates a &#34;blank&#34; iterator, which, when called, pushes itself to the next-stack. :iter does the same thing but allows you to write some code that accepts parameters and prepares the loop stacks first. :next defines a new anonymous &#34;next-word&#34; and assigns it to the most-recently defined iterator. :cancel does the same thing, but for cancellation.&#xA;&#xA;On its own, this is already quite nice. I&#39;ve got a page or so of basically-trivial iterators. Here&#39;s one:&#xA;&#xA;:iter times ( n -- )   i ;&#xA;:next i dup 1- i finish? ;&#xA;:cancel idrop nextdrop ;&#xA;&#xA;times keeps its state in the i-stack - it initializes itself by pushing the number of times to repeat onto it. When fetching the next value, it pops the current value off the i-stack, decrements it, and pushes it back, leaving the old value on the data stack. finish? is a simple helper word that peeks at the top of the stack and runs the current cancellation function if it&#39;s false, or in this case, if we&#39;ve already hit 0. Since cleaning up after an iterator is often the same job whether you&#39;re exiting early or not, this word is very handy. Explicitly defining cancellation for this iterator isn&#39;t actually necessary in my current implementation, because idrop nextdrop is common enough that I use it as the default.&#xA;&#xA;each / next&#xA;&#xA;I can use these iteration words (within a compiled definition) like this:&#xA;&#xA;5 times each i . next&#xA;( outputs: 4 3 2 1 0 )&#xA;&#xA;All the common loop types are easy to build in this system, as well as some uncommon ones:&#xA;&#xA;5 10 for each i . next ( outputs: 5 6 7 8 9 )&#xA;0 10 2 for+ each i . next ( outputs: 0 2 4 6 8 )&#xA;( pchars yields pointers to each byte in a zero-terminated string )&#xA;s&#34; hello&#34; pchars each i b@ emit next ( outputs: hello )&#xA;&#xA;Generic cancellation, of course, allows us to trivially implement break; just cancel the iteration at the top of the stack, and then jump to the each loop exit point, after next. continue is even simpler, just jump back to the top of the loop.&#xA;&#xA;5 times each i 3 &lt; if break then i . next ( outputs: 4 3 )&#xA;5 times each i 2 % if continue then i . next ( outputs 4 2 0 )&#xA;&#xA;Under the hood, each just calls the &#34;next-word&#34; of the iterator and jumps to the end of the loop if it returns 0 - conceptually identical to begin iterate while, with next meaning the same thing as repeat. This allows for iterators that return no values.&#xA;&#xA;0 times each i . next ( outputs: )&#xA;&#xA;Generators&#xA;&#xA;That&#39;s nice, but it&#39;s not exactly setting the world on fire; it&#39;s a fair amount of work just to end up with a few different ways of writing &#34;for&#34; loops in practice, that Forth systems have had forever anyway. Is it really worth the cost of this abstraction?&#xA;&#xA;Turns out, absolutely, yes, it is, because you can also build generators on it, and that blows things wide open.&#xA;&#xA;First, a simple example:&#xA;&#xA;: 5-2-8 (( 5 yield 2 yield 8 yield )) ;&#xA;5-2-8 each i . next ( outputs: 5 2 8 )&#xA;&#xA;(( defines the start of the generator, and )) defines the end (and pushes it onto the next-stack). Any valid Forth code goes in between. yield takes the top of the stack, pushes it onto the i-stack, and then suspends the generator until the next iteration. How does this work? Essentially, yield takes the top of the return stack and pushes it onto the next-stack, then pushes an iterator that pops it off the next-stack and pushes it back onto the return stack. The details get a little messier in order to support some more advanced use cases, but that&#39;s the simple idea at the core of it.&#xA;&#xA;OK, neat trick, we&#39;ve built ourselves a nice little coroutine-like system. But wait! It gets better! When yield resumes, it immediately removes all of its state from the iteration stacks. This means that generators can safely interact with any iterator that might be &#34;underneath&#34; it. They can iterate over things and yield in the middle! They can yield different things based on those values! We&#39;ve accidentally built an extremely powerful, totally generic map/filter capability!&#xA;&#xA;: doubled (( each i i + map next )) ;&#xA;5 times doubled each i . next ( outputs: 8 6 4 2 0 )&#xA;: odd (( each i 2 % filter next )) ;&#xA;5 times odd each i . next ( outputs: 3 1 )&#xA;&#xA;map and filter are more yield-like words - it turns out that there&#39;s a number of these that you might want to implement, with different logic for suspending, resuming, and cancelling. map saves the top of the i-stack onto the next-stack and replaces it with the input, restoring the original value after resuming (necessary since the iterator underneath might be using that value as its state). filter conditionally suspends based on the top of the data stack but otherwise doesn&#39;t touch the i-stack, leaving whatever iterator is running underneath to provide the value. Both of these words push iterators with special cancel logic that knows that there is another iterator underneath, and can cancel again recursively once they&#39;ve cleaned themselves up.&#xA;&#xA;Generator state&#xA;&#xA;This design can almost be made to work for generators that have extra state, but it&#39;s awkward and incomplete. You must ensure the data stack is clean whenever you yield, so you&#39;re forced to manually shuffle data to and from the next stack. Consider a filter that only returns values that are divisible by a certain number: &#xA;&#xA;: divisible-by ( n -- )   next &#xA;  (( next each i over % 0 = swap next filter &lt;next next drop )) ;&#xA;5 divisible-by 21 times each i . next ( ouputs: 20 15 10 5 0 )&#xA;&#xA;This works, but there&#39;s so much stack noise! And it breaks down if you need to cancel, because filter has no idea that there&#39;s extra stuff on the next-stack that it needs to clear. Ideally there would be some automatic way of keeping the state of the generator on the data stack while it&#39;s running, and push it safely away when we suspend. Could there be some way to write divisible-by like this?&#xA;&#xA;: divisible-by ( n -- )   arg (( each i over % 0 = filter next drop )) ;&#xA;&#xA;In fact, this code works in my implementation. The scheme to make this happen is a little bit subtle, but it can be done efficiently with a minimum of bookkeeping noise in most cases. I define a variable, gen-arg-count, that starts at zero.   arg is an immediate word that compiles a call to   next and increments that variable. Then, any time I compile a yielding word, I append the value of gen-arg-count to the instruction stream - much like lit. When suspending, the yielding word reads that value out of the instruction stream and transfers that many values from the data stack to the next-stack. Then it moves the pointer to the instruction stream from the return stack to the next-stack, and finally pushes the yielding iterator. That iterator then pulls the instruction pointer back off the next-stack to determine how many values to move from the next-stack back onto the data stack, as well as where to resume the instruction stream. Cancellation similarly can read the arg-count byte to know how many extra values to drop from the next-stack.&#xA;&#xA;Generators need to ensure the data stack is empty before exiting at )). At one point I considered having )) compile the appropriate number of drop calls automatically, but in the end I decided that it&#39;s reasonable and idiomatic to expect a generator to exit with a clean stack, like any other Forth word would.&#xA;&#xA;With this extension, it&#39;s trivial to write all kinds of new iterators - we could even do away with the base iterator system entirely and just express everything as generators. There are lots nice one-line definitions of times:&#xA;&#xA;( 1 ) : times ( n -- )   arg (( begin dup while 1- dup yield repeat drop )) ;&#xA;( 2 ) : times ( n -- )   next (( next begin dup while 1- yield repeat drop )) ;&#xA;( 3 ) : times ( n -- )   arg (( -arg begin dup while 1- yield  repeat drop )) ;&#xA;( 4 ) ( suspend ) &#39; noop ( resume ) &#39; noop ( cancel ) &#39; idrop :yield iyield&#xA;: times ( n -- )   i (( begin i while i 1- i iyield repeat idrop )) ;&#xA;&#xA;Definition 1 doesn&#39;t use anything I haven&#39;t already explained. The state of the iterator is managed on the data stack, and automatically shuffled back and forth from the next-stack by yield.&#xA;&#xA;Definition 2 adds a new word. yield   is a yielder that moves the yielded value from the i-stack back onto the data stack when it resumes, instead of dropping it. The state of the iterator starts on the next-stack but is moved to the i-stack once the iteration loop actually starts.&#xA;&#xA;Definition 3 is virtually the same as 2, but demonstrates the ability to handle changes in the amount of state. -arg is an immediate word that generates no code, but decrements gen-arg-count so that you can express that you&#39;ve consumed the argument and the next yield should preserve one less value on the data stack. (+arg is also defined, performing an increment, in case you generate more values on the stack than you started with.) &#xA;&#xA;Definition 4 is built to keep all state on the i-stack from the beginning. Here we use :yield to define a new yielding word. I realized I hadn&#39;t built a yielder that left the i-stack alone when resuming, but would drop the value when cancelling, so I added one.&#xA;&#xA;All of these options will correctly be cancelled if the code iterating over it calls break, with no special effort!&#xA;&#xA;Final thoughts&#xA;&#xA;With this scheme, generators always take up at least two spaces on the next-stack - one for the yielder&#39;s iterator, and one for the resume point. But if all iterators were defined as generators, and all yielding words had to be defined with :yield to ensure a uniform structure, we could just push the resume point. iterate and cancel could easily find the appropriate function pointer by looking next to the resume point for the address of the yielder and digging inside. I think this could be built in such a way that it would be basically as efficient as the existing scheme, at the cost of making the whole thing more complex to explain. It might be worth pursuing, because generators are so pleasant to read and write, and raw iterators are... less so. I basically never want to write a raw iterator besides the very basic ones that are built-in.&#xA;&#xA;All the source for my Forth system is available online; the iteration system is defined in iter.jrt. There are some interesting examples of generators in embed.jrt, dialer.jrt and rick.jrt - some highlights:&#xA;&#xA;rle-decode - takes a pointer to some run-length encoded packed data, yields a stream of values. Uses the times iterator internally to count off the repeated values.&#xA;menu-options - Provides a dynamic list of items to display in a menu. Yields 2 values at a time - the text to display, and the function to execute when the user selects it.&#xA;xmit-iter - Writes text to the screen with a small delay between each character, to simulate a slow serial connection. An extremely simple loop that can be driven by complex generation logic - including streaming RLE-encoded data with embedded colour information.&#xA;&#xA;#forth #code #essays]]&gt;</description>
      <content:encoded><![CDATA[<p>I recently wrote a small 16-bit Forth for 8086 PCs running DOS. I built the basic one-liner loop words that can trivially be built with just “branch if zero” and “goto”: <code>begin</code>, <code>while</code>, <code>repeat</code>, <code>until</code>, <code>again</code>. But I held off on implementing <code>do</code> / <code>loop</code> at first.</p>

<p>It didn&#39;t seem like too much of a hardship. In a previous Forth I&#39;d built, I&#39;d implemented <code>do</code> / <code>loop</code> using the return stack, but it was... ugly. The code to implement it was ugly, the code it generated was ugly (and large!), and I didn&#39;t find a lot of places where it was actually much nicer to use than explicit <code>begin</code>-based loops. I was able to implement an 8086 assembler and a Minesweeper game without bothering to build <code>do</code> / <code>loop</code>. I didn&#39;t really miss it, but I had a design percolating in the back of my mind that I wanted to try.</p>

<p>At some point I came across some writing that suggested that Forth had a “loop control stack”. Wouldn&#39;t it be nice if I could implement some kind of loop control stack that worked for <em>all</em> kinds of iteration?</p>

<p>The thing I built has blown me away with how flexible, composable, and useful it&#39;s turned out to be. It&#39;s <em>way</em> more powerful than I was expecting. And the code that leverages it is inevitably much simpler and easier to read. </p>

<h2 id="the-stacks">The Stacks</h2>

<p>I added <em>two</em> loop control stacks – what I call the <code>i-stack</code>, and the <code>next-stack</code>. The <code>i-stack</code> contains the current value(s) being iterated over, and is read from with the <code>i</code> and <code>j</code> words like normal. The <code>next-stack</code> is where the magic happens.</p>

<p>When iterating, the top value of the <code>next-stack</code> is a pointer to a small structure called an iterator. It&#39;s a very simple structure, only two cells. The first cell contains the execution token of a word that will either update the current values on the <code>i-stack</code> and return true, or remove its state from both stacks and return false. The second cell points to a cancellation function, that cleans up whatever state the iterator has kept on the two stacks without iterating further, and returns nothing.</p>

<h2 id="iterators">Iterators</h2>

<p>I built some simple helpers for creating iterators. It took a few tries to nail down this design, but I&#39;m happy with it now. <code>defiter</code> creates a “blank” iterator, which, when called, pushes itself to the <code>next-stack</code>. <code>:iter</code> does the same thing but allows you to write some code that accepts parameters and prepares the loop stacks first. <code>:next</code> defines a new anonymous “next-word” and assigns it to the most-recently defined iterator. <code>:cancel</code> does the same thing, but for cancellation.</p>

<p>On its own, this is already quite nice. I&#39;ve got a page or so of basically-trivial iterators. Here&#39;s one:</p>

<pre><code>:iter times ( n -- ) &gt;i ;
:next &lt;i dup 1- &gt;i finish? ;
:cancel idrop nextdrop ;
</code></pre>

<p><code>times</code> keeps its state in the <code>i-stack</code> – it initializes itself by pushing the number of times to repeat onto it. When fetching the next value, it pops the current value off the <code>i-stack</code>, decrements it, and pushes it back, leaving the old value on the data stack. <code>finish?</code> is a simple helper word that peeks at the top of the stack and runs the current cancellation function if it&#39;s false, or in this case, if we&#39;ve already hit 0. Since cleaning up after an iterator is often the same job whether you&#39;re exiting early or not, this word is very handy. Explicitly defining cancellation for this iterator isn&#39;t actually necessary in my current implementation, because <code>idrop nextdrop</code> is common enough that I use it as the default.</p>

<h2 id="each-next">each / next</h2>

<p>I can use these iteration words (within a compiled definition) like this:</p>

<pre><code>5 times each i . next
( outputs: 4 3 2 1 0 )
</code></pre>

<p>All the common loop types are easy to build in this system, as well as some uncommon ones:</p>

<pre><code>5 10 for each i . next ( outputs: 5 6 7 8 9 )
0 10 2 for+ each i . next ( outputs: 0 2 4 6 8 )
( pchars yields pointers to each byte in a zero-terminated string )
s&#34; hello&#34; pchars each i b@ emit next ( outputs: hello )
</code></pre>

<p>Generic cancellation, of course, allows us to trivially implement <code>break</code>; just cancel the iteration at the top of the stack, and then jump to the <code>each</code> loop exit point, after <code>next</code>. <code>continue</code> is even simpler, just jump back to the top of the loop.</p>

<pre><code>5 times each i 3 &lt; if break then i . next ( outputs: 4 3 )
5 times each i 2 % if continue then i . next ( outputs 4 2 0 )
</code></pre>

<p>Under the hood, <code>each</code> just calls the “next-word” of the iterator and jumps to the end of the loop if it returns 0 – conceptually identical to <code>begin iterate while</code>, with <code>next</code> meaning the same thing as <code>repeat</code>. This allows for iterators that return no values.</p>

<pre><code>0 times each i . next ( outputs: )
</code></pre>

<h2 id="generators">Generators</h2>

<p>That&#39;s <em>nice</em>, but it&#39;s not exactly setting the world on fire; it&#39;s a fair amount of work just to end up with a few different ways of writing “for” loops in practice, that Forth systems have had forever anyway. Is it really worth the cost of this abstraction?</p>

<p>Turns out, absolutely, yes, it is, because you can also build generators on it, and that blows things <em>wide</em> open.</p>

<p>First, a simple example:</p>

<pre><code>: 5-2-8 (( 5 yield 2 yield 8 yield )) ;
5-2-8 each i . next ( outputs: 5 2 8 )
</code></pre>

<p><code>((</code> defines the start of the generator, and <code>))</code> defines the end (and pushes it onto the <code>next-stack</code>). <em>Any valid Forth code goes in between</em>. <code>yield</code> takes the top of the stack, pushes it onto the <code>i-stack</code>, and then <em>suspends the generator</em> until the next iteration. How does this work? Essentially, <code>yield</code> takes the top of the return stack and pushes it onto the <code>next-stack</code>, then pushes an iterator that pops it off the <code>next-stack</code> and pushes it back onto the return stack. The details get a little messier in order to support some more advanced use cases, but that&#39;s the simple idea at the core of it.</p>

<p>OK, neat trick, we&#39;ve built ourselves a nice little coroutine-like system. But wait! It gets better! When <code>yield</code> resumes, it immediately removes all of its state from the iteration stacks. This means that <em>generators can safely interact with any iterator that might be “underneath” it</em>. They can iterate over things and yield in the middle! They can yield <em>different things</em> based on those values! We&#39;ve accidentally built an extremely powerful, totally generic map/filter capability!</p>

<pre><code>: doubled (( each i i + map next )) ;
5 times doubled each i . next ( outputs: 8 6 4 2 0 )
: odd (( each i 2 % filter next )) ;
5 times odd each i . next ( outputs: 3 1 )
</code></pre>

<p><code>map</code> and <code>filter</code> are more <code>yield</code>-like words – it turns out that there&#39;s a number of these that you might want to implement, with different logic for suspending, resuming, and cancelling. <code>map</code> saves the top of the <code>i-stack</code> onto the <code>next-stack</code> and replaces it with the input, restoring the original value after resuming (necessary since the iterator underneath might be using that value as its state). <code>filter</code> conditionally suspends based on the top of the data stack but otherwise doesn&#39;t touch the <code>i-stack</code>, leaving whatever iterator is running underneath to provide the value. Both of these words push iterators with special <code>cancel</code> logic that knows that there is another iterator underneath, and can <code>cancel</code> again recursively once they&#39;ve cleaned themselves up.</p>

<h2 id="generator-state">Generator state</h2>

<p>This design can <em>almost</em> be made to work for generators that have extra state, but it&#39;s awkward and incomplete. You must ensure the data stack is clean whenever you yield, so you&#39;re forced to manually shuffle data to and from the next stack. Consider a filter that only returns values that are divisible by a certain number:</p>

<pre><code>: divisible-by ( n -- ) &gt;next 
  (( &lt;next each i over % 0 = swap &gt;next filter &lt;next next drop )) ;
5 divisible-by 21 times each i . next ( ouputs: 20 15 10 5 0 )
</code></pre>

<p>This works, but there&#39;s so much stack noise! And it breaks down if you need to cancel, because <code>filter</code> has no idea that there&#39;s extra stuff on the <code>next-stack</code> that it needs to clear. Ideally there would be some automatic way of keeping the state of the generator on the data stack while it&#39;s running, and push it safely away when we suspend. Could there be some way to write <code>divisible-by</code> like this?</p>

<pre><code>: divisible-by ( n -- ) &gt;arg (( each i over % 0 = filter next drop )) ;
</code></pre>

<p>In fact, this code works in my implementation. The scheme to make this happen is a little bit subtle, but it can be done efficiently with a minimum of bookkeeping noise in most cases. I define a variable, <code>gen-arg-count</code>, that starts at zero. <code>&gt;arg</code> is an immediate word that compiles a call to <code>&gt;next</code> and increments that variable. Then, any time I compile a yielding word, I append the value of <code>gen-arg-count</code> to the instruction stream – much like <code>lit</code>. When suspending, the yielding word reads that value out of the instruction stream and transfers that many values from the data stack to the <code>next-stack</code>. Then it moves the pointer to the instruction stream from the return stack to the <code>next-stack</code>, and finally pushes the yielding iterator. That iterator then pulls the instruction pointer back off the <code>next-stack</code> to determine how many values to move from the <code>next-stack</code> back onto the data stack, as well as where to resume the instruction stream. Cancellation similarly can read the <code>arg-count</code> byte to know how many extra values to drop from the <code>next-stack</code>.</p>

<p>Generators need to ensure the data stack is empty before exiting at <code>))</code>. At one point I considered having <code>))</code> compile the appropriate number of <code>drop</code> calls automatically, but in the end I decided that it&#39;s reasonable and idiomatic to expect a generator to exit with a clean stack, like any other Forth word would.</p>

<p>With this extension, it&#39;s trivial to write all kinds of new iterators – we could even do away with the base iterator system entirely and just express everything as generators. There are lots nice one-line definitions of <code>times</code>:</p>

<pre><code>( 1 ) : times ( n -- ) &gt;arg (( begin dup while 1- dup yield repeat drop )) ;
( 2 ) : times ( n -- ) &gt;next (( &lt;next begin dup while 1- yield&gt; repeat drop )) ;
( 3 ) : times ( n -- ) &gt;arg (( -arg begin dup while 1- yield&gt; repeat drop )) ;
( 4 ) ( suspend ) &#39; noop ( resume ) &#39; noop ( cancel ) &#39; idrop :yield iyield
: times ( n -- ) &gt;i (( begin i while &lt;i 1- &gt;i iyield repeat idrop )) ;
</code></pre>

<p>Definition 1 doesn&#39;t use anything I haven&#39;t already explained. The state of the iterator is managed on the data stack, and automatically shuffled back and forth from the <code>next-stack</code> by <code>yield</code>.</p>

<p>Definition 2 adds a new word. <code>yield&gt;</code> is a yielder that moves the yielded value from the <code>i-stack</code> back onto the data stack when it resumes, instead of dropping it. The state of the iterator starts on the <code>next-stack</code> but is moved to the <code>i-stack</code> once the iteration loop actually starts.</p>

<p>Definition 3 is virtually the same as 2, but demonstrates the ability to handle changes in the amount of state. <code>-arg</code> is an immediate word that generates no code, but decrements <code>gen-arg-count</code> so that you can express that you&#39;ve consumed the argument and the next yield should preserve one less value on the data stack. (<code>+arg</code> is also defined, performing an increment, in case you generate more values on the stack than you started with.)</p>

<p>Definition 4 is built to keep all state on the <code>i-stack</code> from the beginning. Here we use <code>:yield</code> to define a new yielding word. I realized I hadn&#39;t built a yielder that left the <code>i-stack</code> alone when resuming, but would drop the value when cancelling, so I added one.</p>

<p>All of these options will correctly be cancelled if the code iterating over it calls <code>break</code>, with no special effort!</p>

<h2 id="final-thoughts">Final thoughts</h2>

<p>With this scheme, generators always take up at least two spaces on the <code>next-stack</code> – one for the yielder&#39;s iterator, and one for the resume point. But if <em>all</em> iterators were defined as generators, and all yielding words had to be defined with <code>:yield</code> to ensure a uniform structure, we could just push the resume point. <code>iterate</code> and <code>cancel</code> could easily find the appropriate function pointer by looking next to the resume point for the address of the yielder and digging inside. I think this could be built in such a way that it would be basically as efficient as the existing scheme, at the cost of making the whole thing more complex to explain. It might be worth pursuing, because generators are so pleasant to read and write, and raw iterators are... less so. I basically never want to write a raw iterator besides the very basic ones that are built-in.</p>

<p>All <a href="https://git.information-superhighway.net/SpindleyQ/dialer">the source for my Forth system</a> is available online; the iteration system is defined in <a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/branch/main/iter.jrt"><code>iter.jrt</code></a>. There are some interesting examples of generators in <a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/branch/main/embed.jrt"><code>embed.jrt</code></a>, <a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/branch/main/dialer.jrt"><code>dialer.jrt</code></a> and <a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/branch/main/rick.jrt"><code>rick.jrt</code></a> – some highlights:</p>
<ul><li><a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/commit/17ae93540901e7c4259aa81463fa540dc36769ad/embed.jrt#L47"><code>rle-decode</code></a> – takes a pointer to some run-length encoded packed data, yields a stream of values. Uses the <code>times</code> iterator internally to count off the repeated values.</li>
<li><a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/commit/17ae93540901e7c4259aa81463fa540dc36769ad/dialer.jrt#L222"><code>menu-options</code></a> – Provides a dynamic list of items to display in a menu. Yields 2 values at a time – the text to display, and the function to execute when the user selects it.</li>
<li><a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/commit/17ae93540901e7c4259aa81463fa540dc36769ad/dialer.jrt#L111"><code>xmit-iter</code></a> – Writes text to the screen with a small delay between each character, to simulate a slow serial connection. An extremely simple loop that can be driven by complex generation logic – including <a href="https://git.information-superhighway.net/SpindleyQ/dialer/src/commit/17ae93540901e7c4259aa81463fa540dc36769ad/dialer.jrt#L211">streaming RLE-encoded data with embedded colour information</a>.</li></ul>

<p><a href="https://blog.information-superhighway.net/tag:forth" class="hashtag"><span>#</span><span class="p-category">forth</span></a> <a href="https://blog.information-superhighway.net/tag:code" class="hashtag"><span>#</span><span class="p-category">code</span></a> <a href="https://blog.information-superhighway.net/tag:essays" class="hashtag"><span>#</span><span class="p-category">essays</span></a></p>
]]></content:encoded>
      <guid>https://blog.information-superhighway.net/a-forth-vocabulary-for-iteration</guid>
      <pubDate>Wed, 08 Nov 2023 14:35:58 +0000</pubDate>
    </item>
    <item>
      <title>Forth: The local variable question</title>
      <link>https://blog.information-superhighway.net/forth-the-local-variable-question</link>
      <description>&lt;![CDATA[I fairly frequently see people who are taking an interest in Forth struggle with the idea of programming without local variables. I struggled with it when I started writing Forth! I feel like there&#39;s an unspoken assumption for people coming to Forth from other languages, and if I were to speak it aloud, it would sound something like &#34;temporary data should go on the stack&#34;.&#xA;&#xA;Because... functions should be re-entrant by default! They should clean up after themselves! Global variables are bad and must be avoided at all costs! Functions should be &#34;pure&#34; and take all of their inputs as parameters, avoiding hidden dependencies!&#xA;&#xA;All of these ideas of what &#34;good code&#34; looks like are wrong in Forth.&#xA;&#xA;It is actually extremely common for Forth words to rely on implicit context, which is globally accessible through other Forth words. This is often how you build DSLs! !--more--&#xA;&#xA;Perhaps you are familiar with the JavaScript canvas API. It&#39;s based on PostScript, as are most vector drawing APIs, and PostScript, as you may know, is a Forth-like postfix language for printed graphics. The canvas API has a bunch of implicit state. When you draw a rectangle, for example, you pass in just the position and size. If you want to specify properties like the fill colour, stroke colour, stroke width, line cap style, and on and on and on, you call setter methods before calling the draw function. If you want to preserve the previous canvas state and return to it when you&#39;re done, you can explicitly push it onto a stack.&#xA;&#xA;This is one secret sauce to writing small Forth words - you build little vocabularies that all work with some kernel of shared state.&#xA;&#xA;Let&#39;s implement Bresenham&#39;s line algorithm&#xA;&#xA;I had the idea to implement an algorithm where juggling all of the state on the stack would be a nightmare, to show an example of what this looks like in practice. I&#39;ve always found Bresenham&#39;s line-drawing algorithm kind of awkward - most implementations in C switch between several nearly-identical code blocks depending on how steep the line is. But the core idea is actually very simple, and the awkward near-duplication of the standard C implementation does not have to be reproduced in Forth.&#xA;&#xA;First we will define a simple textual canvas vocabulary:&#xA;&#xA;80 CONSTANT SCREEN-W &#xA;24 CONSTANT SCREEN-H&#xA;CREATE SCREEN SCREEN-W SCREEN-H  ALLOT&#xA;CREATE SCREEN-BRUSH KEY + C,&#xA;&#xA;: SET-BRUSH ( -- ) KEY SCREEN-BRUSH C! ;&#xA;: FILL-SCREEN ( -- ) SCREEN-W SCREEN-H  SCREEN + SCREEN DO I SCREEN-BRUSH C@ SWAP C! LOOP ;&#xA;: SCREEN-XY ( x y -- ptr ) SCREEN-W  + SCREEN + ;&#xA;: PLOT-XY ( x y -- ) SCREEN-XY SCREEN-BRUSH C@ SWAP C! ;&#xA;: PRINT-ROW ( y -- ) 0 SWAP SCREEN-XY SCREEN-W TYPE ;&#xA;: PRINT-SCREEN SCREEN-H 0 DO I PRINT-ROW CR LOOP ;&#xA;&#xA;This is ANS Forth - my personal Forths have all been lowercase, I don&#39;t usually like all the shouting.&#xA;&#xA;This creates a buffer called SCREEN that is 80 columns wide by 24 rows tall. It also defines the concept of a brush, which is just an ASCII character that is put into this buffer by PLOT-XY. Our line-drawing routine will use PLOT-XY to put &#34;pixels&#34; on the &#34;screen&#34; without caring about what they look like. Kind of a canvassy idea.&#xA;&#xA;Now let&#39;s clear the screen:&#xA;&#xA;SET-BRUSH +&#xA;FILL-SCREEN &#xA;SET-BRUSH $&#xA;&#xA;I use the + character for &#34;off&#34; and the $ character for &#34;on&#34; because they were about the same width in the variable-width font that my browser picked when plugging this code into jsForth. The trick where SET-BRUSH reads the next character in the code directly is cute but brittle; it only works interactively and will break weirdly in a : definition. WAForth can&#39;t handle it at all, it pops up a dialog box asking for you to type a character. Feel free to use 43 SCREEN-BRUSH C! to draw with + and 36 SCREEN-BRUSH C! to draw with $ if you want to follow along in WAForth. Define little helper words for them even, like BRUSH-+ and BRUSH-$. It&#39;s not a big problem, don&#39;t overthink it, but do make yourself comfortable.&#xA;&#xA;An aside: How to draw a line&#xA;&#xA;So let&#39;s talk for a minute about how Bresenham&#39;s line-drawing algorithm works. The Wikipedia article has a bunch of math and symbols but at its core it&#39;s really very simple. Start with a specific kind of line, that slopes upwards and to the right, but not steeper than 45 degrees.&#xA;&#xA;Start at the bottom-left side of the line. Draw that pixel.&#xA;Move your X coordinate one to the right. Now you need to decide if the Y coordinate needs to move up one or stay where it is.&#xA;To do that, you keep track of a subpixel fraction; ie. you start in the middle of a pixel (0.5), and increment it by the amount that the line has risen over the last pixel: (y2-y1)/(x2-x1) or dy/dx.&#xA;If the fraction is   1, move Y up one pixel and subtract 1 from the fraction; the fraction value is now somewhere within the bottom half of the next highest pixel.&#xA;Now draw the next pixel and go back to step 2 until you end up at the top-right end of the line.&#xA;&#xA;This is very simple! We then layer on just a few simple tricks:&#xA;&#xA;Instead of always moving along the X axis, for lines that are taller than they are long, we need to move along the Y axis. To do this we simply always move in the direction of the longer side, and run the decision logic along the shorter axis. This way the slope is never steeper than 45 degrees.&#xA;If, for example, the line slopes down instead of up, when we decide whether to move along the Y axis, we need to move down one pixel instead of up. We can handle this by simply incrementing instead of decrementing along the appropriate axis.&#xA;In the olden days, floating point numbers were very slow and integers were fast. Since the &#34;error&#34; value (really a fractional pixel location, but everyone calls it &#34;error&#34;) always has the same denominator, and we don&#39;t do anything more complicated than adding more fractions with the same denominator to it, we can just keep the denominator implicit and store the numerator in an integer. We choose 2  dx (when x is the long axis) as the denominator so that we can easily start exactly on a half pixel (ie. our starting value is dx/2dx, and we increment by 2  dy every step). It doesn&#39;t actually make a huge amount of difference what you use for a starting value though, as long as it&#39;s smaller than your implicit denominator then you&#39;ll end up with a line that starts and ends where you expect.&#xA;&#xA;That&#39;s it! That&#39;s the whole thing.&#xA;&#xA;Now back to writing Forth&#xA;&#xA;So, first off, let&#39;s define the state that we&#39;ll need. Starting and ending X and Y coordinates, the current X and Y coordinates, and the fractional &#34;error&#34; value. Definitely need to remember all that.&#xA;&#xA;VARIABLE LINE-X1 VARIABLE LINE-Y1 &#xA;VARIABLE LINE-X2 VARIABLE LINE-Y2&#xA;VARIABLE LINE-X  VARIABLE LINE-Y  VARIABLE LINE-ERR&#xA;&#xA;Now we can start defining helper words. Let&#39;s write a couple of words to figure out the length of the line along each axis:&#xA;&#xA;: LINE-DX ( -- dx ) LINE-X2 @ LINE-X1 @ - ;&#xA;: LINE-DY ( -- dy ) LINE-Y2 @ LINE-Y1 @ - ;&#xA;&#xA;No sweat; just take x2 - x1 or y2 - y1. How about some words to decide which axis is longer, and what direction each axis is moving in?&#xA;&#xA;: X-LONGER? ( -- f ) LINE-DX ABS LINE-DY ABS   ;&#xA;: LINE-LEFT? ( -- f ) LINE-DX 0 &lt; ;&#xA;: LINE-UP? ( -- f ) LINE-DY 0 &lt; ;&#xA;&#xA;Even if you&#39;re not well-practiced reading postfix, I hope it&#39;s pretty clear what these are doing.&#xA;&#xA;Now let&#39;s define some words for incrementing or decrementing, depending on which direction the line is going:&#xA;&#xA;: LINE-XINC ( x -- x ) LINE-LEFT? IF 1- ELSE 1+ THEN ;&#xA;: LINE-YINC ( y -- y ) LINE-UP? IF 1- ELSE 1+ THEN ;&#xA;: LINE-INC ( x|y x? -- x|y ) IF LINE-XINC ELSE LINE-YINC THEN ;&#xA;&#xA;LINE-INC is our first and only word to take two values on the stack - the top is a boolean that determines if we&#39;re talking about the X or Y axis. We will soon use it in conjunction with X-LONGER? to abstract away incrementing the &#34;long&#34;&#xA;vs. &#34;short&#34; axis.&#xA;&#xA;: LINE-LONG ( -- p ) X-LONGER? IF LINE-X ELSE LINE-Y THEN ;&#xA;: LINE-SHORT ( -- p ) X-LONGER? 0= IF LINE-X ELSE LINE-Y THEN ;&#xA;: LINE-LONG-INC! ( -- ) LINE-LONG @ X-LONGER? LINE-INC LINE-LONG ! ;&#xA;: LINE-SHORT-INC! ( -- ) LINE-SHORT @ X-LONGER? 0= LINE-INC LINE-SHORT ! ;&#xA;&#xA;LINE-LONG-INC! is a little tricky, so let&#39;s walk through it:&#xA;&#xA;LINE-LONG returns a pointer to either the LINE-X or LINE-Y variable. &#xA;@ fetches the current coordinate along the long axis. &#xA;X-LONGER? pushes &#34;true&#34; onto the stack if X is the long axis (and thus the X coordinate is what&#39;s on the stack)&#xA;LINE-INC calls LINE-XINC if X is long, or LINE-YINC if Y is long. This increments or decrements the value, depending on the direction of the line. The new coordinate is the one value left on the stack.&#xA;LINE-LONG ! fetches the appropriate pointer again and stores the new value.&#xA;&#xA;LINE-SHORT-INC! is basically the same, except with an 0= in there as a &#34;logical not&#34; for X-LONGER?. (It didn&#39;t quite seem worthwhile to define Y-LONGER? on its own.)&#xA;&#xA;Now let&#39;s define some useful words for the error / fractional pixel calculation:&#xA;&#xA;: LINE-LONG-LEN ( -- l ) X-LONGER? IF LINE-DX ELSE LINE-DY THEN ABS ;&#xA;: LINE-SHORT-LEN ( -- l ) X-LONGER? IF LINE-DY ELSE LINE-DX THEN ABS ;&#xA;: LINE-LONG-ERR ( -- err ) LINE-LONG-LEN 2  ;&#xA;: LINE-SHORT-ERR ( -- err ) LINE-SHORT-LEN 2  ;&#xA;: LINE-INIT-ERR! ( -- ) LINE-LONG-LEN LINE-ERR ! ;&#xA;: LINE-ERR-ACC ( -- err ) LINE-ERR @ LINE-SHORT-ERR + ;&#xA;&#xA;LINE-INIT-ERR! defines the initial error value as half a pixel (with LINE-LONG-ERR being the implicit denominator). LINE-ERR-ACC fetches the current error and adds the appropriate fraction along the short axis, leaving the new value on the stack.&#xA;&#xA;: LINE-ERR-INC! ( err -- err ) DUP LINE-LONG-ERR   = IF LINE-LONG-ERR - LINE-SHORT-INC! THEN ;&#xA;: LINE-ERR-ACC! ( -- ) LINE-ERR-ACC LINE-ERR-INC! LINE-ERR ! ;&#xA;: LINE-STEP ( -- ) LINE-LONG-INC! LINE-ERR-ACC! ;&#xA;&#xA;LINE-ERR-INC! takes the incremented error value, determines if we&#39;ve overflown the fraction into the next pixel, and if so, decrements the error value and increments the coordinate along the short axis. The updated error value is left on the stack. This is the only place in the algorithm where I chose to use a stack-manipulation word.* I could have gotten by without it by just calling LINE-ERR-ACC a couple of times, but it would have made the definition longer and arguably harder to follow.&#xA;&#xA;LINE-ERR-ACC! handles accumulating the error, incrementing the short axis if necessary, and storing the new error. Finally, LINE-STEP puts all the core logic together - increment along the long axis, then decide whether we need to increment along the short axis.&#xA;&#xA;All that&#39;s left is to run it in a loop:&#xA;&#xA;: PLOT-LINE-STEP ( -- ) LINE-X @ LINE-Y @ PLOT-XY ;&#xA;: DO-LINE ( -- ) LINE-INIT-ERR! LINE-LONG-LEN 0 DO PLOT-LINE-STEP LINE-STEP LOOP PLOT-LINE-STEP ;&#xA;&#xA;: LINE ( x1 y1 x2 y2 -- ) &#xA;  LINE-Y2 ! LINE-X2 ! DUP LINE-Y ! LINE-Y1 ! DUP LINE-X ! LINE-X1 ! DO-LINE ;&#xA;&#xA;The final definition of LINE takes four values on the stack and immediately puts them into variables that are used by all the other words.&#xA;&#xA;IMO, this is what Forth enthusiasts mean when they say things like &#34;write lots of small definitions&#34;, or &#34;the stack shouldn&#39;t need to be very deep&#34;, or &#34;you don&#39;t need local variables&#34;. There are 24 one line function definitions up there. No individual definition is particularly complicated or hard to read. We do virtually no stack manipulation.&#xA;&#xA;Let&#39;s see it in action!&#xA;&#xA;0 0 0 15 LINE&#xA;0 0 15 15 LINE&#xA;30 15 0 0 LINE&#xA;60 15 0 0 LINE&#xA;79 7 0 0 LINE&#xA;79 7 60 15 LINE&#xA;0 15 60 15 LINE&#xA;&#xA;PRINT-SCREEN&#xA;$$$$$$++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;$$$$$$$$$$$$$$$$$+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;$+$+$$+$$$$++++++$$$$$$$$$$$$+++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;$++$++$$+++$$$$++++++++++++++$$$$$$$$$$$++++++++++++++++++++++++++++++++++++++++&#xA;$+++$+++$$+++++$$$$+++++++++++++++++++++$$$$$$$$$$$+++++++++++++++++++++++++++++&#xA;$++++$++++$$+++++++$$$$++++++++++++++++++++++++++++$$$$$$$$$$$$+++++++++++++++++&#xA;$+++++$+++++$$+++++++++$$$$++++++++++++++++++++++++++++++++++++$$$$$$$$$$$++++++&#xA;$++++++$++++++$$+++++++++++$$$$+++++++++++++++++++++++++++++++++++++++++++$$$$$$&#xA;$+++++++$+++++++$$+++++++++++++$$$$+++++++++++++++++++++++++++++++++++++++++$$++&#xA;$++++++++$++++++++$$+++++++++++++++$$$$+++++++++++++++++++++++++++++++++++$$++++&#xA;$+++++++++$+++++++++$$+++++++++++++++++$$$$++++++++++++++++++++++++++++$$$++++++&#xA;$++++++++++$++++++++++$$+++++++++++++++++++$$$$++++++++++++++++++++++$$+++++++++&#xA;$+++++++++++$+++++++++++$$+++++++++++++++++++++$$$$+++++++++++++++$$$+++++++++++&#xA;$++++++++++++$++++++++++++$$+++++++++++++++++++++++$$$$+++++++++$$++++++++++++++&#xA;$+++++++++++++$+++++++++++++$$+++++++++++++++++++++++++$$$$+++$$++++++++++++++++&#xA;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&#xA;&#xA;Lovely!&#xA;&#xA;Now, there is plenty to criticize about this code. It does all kinds of redundant recalculation that in any sane C implementation would have been stashed away into a local, for example. But that&#39;s fixable with a little more effort; I might do another blog post where I apply some of Forth&#39;s fun metaprogramming tricks to that problem. &#xA;&#xA;#forth #essays #code]]&gt;</description>
      <content:encoded><![CDATA[<p>I fairly frequently see people who are taking an interest in Forth struggle with the idea of programming without local variables. I struggled with it when I started writing Forth! I feel like there&#39;s an unspoken assumption for people coming to Forth from other languages, and if I were to speak it aloud, it would sound something like “temporary data should go on the stack”.</p>

<p>Because... functions should be re-entrant by default! They should clean up after themselves! Global variables are bad and must be avoided at all costs! Functions should be “pure” and take all of their inputs as parameters, avoiding hidden dependencies!</p>

<p>All of these ideas of what “good code” looks like are wrong in Forth.</p>

<p>It is actually extremely common for Forth words to rely on implicit context, which is globally accessible through other Forth words. This is often how you build DSLs! </p>

<p>Perhaps you are familiar with the JavaScript <code>canvas</code> API. It&#39;s based on PostScript, as are most vector drawing APIs, and PostScript, as you may know, is a Forth-like postfix language for printed graphics. The <code>canvas</code> API has a <em>bunch</em> of implicit state. When you draw a rectangle, for example, you pass in just the position and size. If you want to specify properties like the fill colour, stroke colour, stroke width, line cap style, and on and on and on, you call setter methods before calling the draw function. If you want to preserve the previous canvas state and return to it when you&#39;re done, you can explicitly push it onto a stack.</p>

<p>This is one secret sauce to writing small Forth words – you build little vocabularies that all work with some kernel of shared state.</p>

<h2 id="let-s-implement-bresenham-s-line-algorithm">Let&#39;s implement Bresenham&#39;s line algorithm</h2>

<p>I had the idea to implement an algorithm where juggling all of the state on the stack would be a nightmare, to show an example of what this looks like in practice. I&#39;ve always found Bresenham&#39;s line-drawing algorithm kind of awkward – most implementations in C switch between several nearly-identical code blocks depending on how steep the line is. But the core idea is actually very simple, and the awkward near-duplication of the standard C implementation does not have to be reproduced in Forth.</p>

<p>First we will define a simple textual canvas vocabulary:</p>

<pre><code>80 CONSTANT SCREEN-W 
24 CONSTANT SCREEN-H
CREATE SCREEN SCREEN-W SCREEN-H * ALLOT
CREATE SCREEN-BRUSH KEY + C,

: SET-BRUSH ( -- ) KEY SCREEN-BRUSH C! ;
: FILL-SCREEN ( -- ) SCREEN-W SCREEN-H * SCREEN + SCREEN DO I SCREEN-BRUSH C@ SWAP C! LOOP ;
: SCREEN-XY ( x y -- ptr ) SCREEN-W * + SCREEN + ;
: PLOT-XY ( x y -- ) SCREEN-XY SCREEN-BRUSH C@ SWAP C! ;
: PRINT-ROW ( y -- ) 0 SWAP SCREEN-XY SCREEN-W TYPE ;
: PRINT-SCREEN SCREEN-H 0 DO I PRINT-ROW CR LOOP ;
</code></pre>

<p>This is ANS Forth – my personal Forths have all been lowercase, I don&#39;t usually like all the shouting.</p>

<p>This creates a buffer called <code>SCREEN</code> that is 80 columns wide by 24 rows tall. It also defines the concept of a brush, which is just an ASCII character that is put into this buffer by <code>PLOT-XY</code>. Our line-drawing routine will use <code>PLOT-XY</code> to put “pixels” on the “screen” without caring about what they look like. Kind of a canvassy idea.</p>

<p>Now let&#39;s clear the screen:</p>

<pre><code>SET-BRUSH +
FILL-SCREEN 
SET-BRUSH $
</code></pre>

<p>I use the <code>+</code> character for “off” and the <code>$</code> character for “on” because they were about the same width in the variable-width font that my browser picked when plugging this code into <a href="https://brendanator.github.io/jsForth/">jsForth</a>. The trick where <code>SET-BRUSH</code> reads the next character in the code directly is cute but brittle; it only works interactively and will break weirdly in a <code>:</code> definition. <a href="https://el-tramo.be/waforth/">WAForth</a> can&#39;t handle it at all, it pops up a dialog box asking for you to type a character. Feel free to use <code>43 SCREEN-BRUSH C!</code> to draw with <code>+</code> and <code>36 SCREEN-BRUSH C!</code> to draw with <code>$</code> if you want to follow along in WAForth. Define little helper words for them even, like <code>BRUSH-+</code> and <code>BRUSH-$</code>. It&#39;s not a big problem, don&#39;t overthink it, but do make yourself comfortable.</p>

<h3 id="an-aside-how-to-draw-a-line">An aside: How to draw a line</h3>

<p>So let&#39;s talk for a minute about how Bresenham&#39;s line-drawing algorithm works. The Wikipedia article has a bunch of math and symbols but at its core it&#39;s really very simple. Start with a specific kind of line, that slopes upwards and to the right, but not steeper than 45 degrees.</p>
<ol><li>Start at the bottom-left side of the line. Draw that pixel.</li>
<li>Move your X coordinate one to the right. Now you need to decide if the Y coordinate needs to move up one or stay where it is.</li>
<li>To do that, you keep track of a subpixel fraction; ie. you start in the middle of a pixel (0.5), and increment it by the amount that the line has risen over the last pixel: (y2-y1)/(x2-x1) or dy/dx.</li>
<li>If the fraction is &gt;1, move Y up one pixel and subtract 1 from the fraction; the fraction value is now somewhere within the bottom half of the next highest pixel.</li>
<li>Now draw the next pixel and go back to step 2 until you end up at the top-right end of the line.</li></ol>

<p>This is very simple! We then layer on just a few simple tricks:</p>
<ul><li>Instead of always moving along the X axis, for lines that are taller than they are long, we need to move along the Y axis. To do this we simply always move in the direction of the longer side, and run the decision logic along the shorter axis. This way the slope is never steeper than 45 degrees.</li>
<li>If, for example, the line slopes down instead of up, when we decide whether to move along the Y axis, we need to move down one pixel instead of up. We can handle this by simply incrementing instead of decrementing along the appropriate axis.</li>
<li>In the olden days, floating point numbers were very slow and integers were fast. Since the “error” value (really a fractional pixel location, but everyone calls it “error”) always has the same denominator, and we don&#39;t do anything more complicated than adding more fractions with the same denominator to it, we can just keep the denominator implicit and store the numerator in an integer. We choose <code>2 * dx</code> (when x is the long axis) as the denominator so that we can easily start exactly on a half pixel (ie. our starting value is <code>dx/2dx</code>, and we increment by <code>2 * dy</code> every step). It doesn&#39;t actually make a huge amount of difference what you use for a starting value though, as long as it&#39;s smaller than your implicit denominator then you&#39;ll end up with a line that starts and ends where you expect.</li></ul>

<p>That&#39;s it! That&#39;s the whole thing.</p>

<h3 id="now-back-to-writing-forth">Now back to writing Forth</h3>

<p>So, first off, let&#39;s define the state that we&#39;ll need. Starting and ending X and Y coordinates, the current X and Y coordinates, and the fractional “error” value. Definitely need to remember all that.</p>

<pre><code>VARIABLE LINE-X1 VARIABLE LINE-Y1 
VARIABLE LINE-X2 VARIABLE LINE-Y2
VARIABLE LINE-X  VARIABLE LINE-Y  VARIABLE LINE-ERR
</code></pre>

<p>Now we can start defining helper words. Let&#39;s write a couple of words to figure out the length of the line along each axis:</p>

<pre><code>: LINE-DX ( -- dx ) LINE-X2 @ LINE-X1 @ - ;
: LINE-DY ( -- dy ) LINE-Y2 @ LINE-Y1 @ - ;
</code></pre>

<p>No sweat; just take <code>x2 - x1</code> or <code>y2 - y1</code>. How about some words to decide which axis is longer, and what direction each axis is moving in?</p>

<pre><code>: X-LONGER? ( -- f ) LINE-DX ABS LINE-DY ABS &gt; ;
: LINE-LEFT? ( -- f ) LINE-DX 0 &lt; ;
: LINE-UP? ( -- f ) LINE-DY 0 &lt; ;
</code></pre>

<p>Even if you&#39;re not well-practiced reading postfix, I hope it&#39;s pretty clear what these are doing.</p>

<p>Now let&#39;s define some words for incrementing or decrementing, depending on which direction the line is going:</p>

<pre><code>: LINE-XINC ( x -- x ) LINE-LEFT? IF 1- ELSE 1+ THEN ;
: LINE-YINC ( y -- y ) LINE-UP? IF 1- ELSE 1+ THEN ;
: LINE-INC ( x|y x? -- x|y ) IF LINE-XINC ELSE LINE-YINC THEN ;
</code></pre>

<p><code>LINE-INC</code> is our first and only word to take <em>two</em> values on the stack – the top is a boolean that determines if we&#39;re talking about the X or Y axis. We will soon use it in conjunction with <code>X-LONGER?</code> to abstract away incrementing the “long”
vs. “short” axis.</p>

<pre><code>: LINE-LONG ( -- p ) X-LONGER? IF LINE-X ELSE LINE-Y THEN ;
: LINE-SHORT ( -- p ) X-LONGER? 0= IF LINE-X ELSE LINE-Y THEN ;
: LINE-LONG-INC! ( -- ) LINE-LONG @ X-LONGER? LINE-INC LINE-LONG ! ;
: LINE-SHORT-INC! ( -- ) LINE-SHORT @ X-LONGER? 0= LINE-INC LINE-SHORT ! ;
</code></pre>

<p><code>LINE-LONG-INC!</code> is a little tricky, so let&#39;s walk through it:</p>
<ul><li><code>LINE-LONG</code> returns a pointer to either the <code>LINE-X</code> or <code>LINE-Y</code> variable.</li>
<li><code>@</code> fetches the current coordinate along the long axis.</li>
<li><code>X-LONGER?</code> pushes “true” onto the stack if X is the long axis (and thus the X coordinate is what&#39;s on the stack)</li>
<li><code>LINE-INC</code> calls <code>LINE-XINC</code> if X is long, or <code>LINE-YINC</code> if Y is long. This increments or decrements the value, depending on the direction of the line. The new coordinate is the one value left on the stack.</li>
<li><code>LINE-LONG !</code> fetches the appropriate pointer again and stores the new value.</li></ul>

<p><code>LINE-SHORT-INC!</code> is basically the same, except with an <code>0=</code> in there as a “logical not” for <code>X-LONGER?</code>. (It didn&#39;t quite seem worthwhile to define <code>Y-LONGER?</code> on its own.)</p>

<p>Now let&#39;s define some useful words for the error / fractional pixel calculation:</p>

<pre><code>: LINE-LONG-LEN ( -- l ) X-LONGER? IF LINE-DX ELSE LINE-DY THEN ABS ;
: LINE-SHORT-LEN ( -- l ) X-LONGER? IF LINE-DY ELSE LINE-DX THEN ABS ;
: LINE-LONG-ERR ( -- err ) LINE-LONG-LEN 2 * ;
: LINE-SHORT-ERR ( -- err ) LINE-SHORT-LEN 2 * ;
: LINE-INIT-ERR! ( -- ) LINE-LONG-LEN LINE-ERR ! ;
: LINE-ERR-ACC ( -- err ) LINE-ERR @ LINE-SHORT-ERR + ;
</code></pre>

<p><code>LINE-INIT-ERR!</code> defines the initial error value as half a pixel (with <code>LINE-LONG-ERR</code> being the implicit denominator). <code>LINE-ERR-ACC</code> fetches the current error and adds the appropriate fraction along the short axis, leaving the new value on the stack.</p>

<pre><code>: LINE-ERR-INC! ( err -- err ) DUP LINE-LONG-ERR &gt;= IF LINE-LONG-ERR - LINE-SHORT-INC! THEN ;
: LINE-ERR-ACC! ( -- ) LINE-ERR-ACC LINE-ERR-INC! LINE-ERR ! ;
: LINE-STEP ( -- ) LINE-LONG-INC! LINE-ERR-ACC! ;
</code></pre>

<p><code>LINE-ERR-INC!</code> takes the incremented error value, determines if we&#39;ve overflown the fraction into the next pixel, and if so, decrements the error value and increments the coordinate along the short axis. The updated error value is left on the stack. <em>This is the only place in the algorithm where I chose to use a stack-manipulation word.</em> I could have gotten by without it by just calling <code>LINE-ERR-ACC</code> a couple of times, but it would have made the definition longer and arguably harder to follow.</p>

<p><code>LINE-ERR-ACC!</code> handles accumulating the error, incrementing the short axis if necessary, and storing the new error. Finally, <code>LINE-STEP</code> puts all the core logic together – increment along the long axis, then decide whether we need to increment along the short axis.</p>

<p>All that&#39;s left is to run it in a loop:</p>

<pre><code>: PLOT-LINE-STEP ( -- ) LINE-X @ LINE-Y @ PLOT-XY ;
: DO-LINE ( -- ) LINE-INIT-ERR! LINE-LONG-LEN 0 DO PLOT-LINE-STEP LINE-STEP LOOP PLOT-LINE-STEP ;

: LINE ( x1 y1 x2 y2 -- ) 
  LINE-Y2 ! LINE-X2 ! DUP LINE-Y ! LINE-Y1 ! DUP LINE-X ! LINE-X1 ! DO-LINE ;
</code></pre>

<p>The final definition of <code>LINE</code> takes four values on the stack and immediately puts them into variables that are used by all the other words.</p>

<p>IMO, this is what Forth enthusiasts mean when they say things like “write lots of small definitions”, or “the stack shouldn&#39;t need to be very deep”, or “you don&#39;t need local variables”. There are <em>24</em> one line function definitions up there. No individual definition is particularly complicated or hard to read. We do virtually no stack manipulation.</p>

<p>Let&#39;s see it in action!</p>

<pre><code>0 0 0 15 LINE
0 0 15 15 LINE
30 15 0 0 LINE
60 15 0 0 LINE
79 7 0 0 LINE
79 7 60 15 LINE
0 15 60 15 LINE

PRINT-SCREEN
</code></pre>

<pre><code>$$$$$$++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
$$$$$$$$$$$$$$$$$+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
$+$+$$+$$$$++++++$$$$$$$$$$$$+++++++++++++++++++++++++++++++++++++++++++++++++++
$++$++$$+++$$$$++++++++++++++$$$$$$$$$$$++++++++++++++++++++++++++++++++++++++++
$+++$+++$$+++++$$$$+++++++++++++++++++++$$$$$$$$$$$+++++++++++++++++++++++++++++
$++++$++++$$+++++++$$$$++++++++++++++++++++++++++++$$$$$$$$$$$$+++++++++++++++++
$+++++$+++++$$+++++++++$$$$++++++++++++++++++++++++++++++++++++$$$$$$$$$$$++++++
$++++++$++++++$$+++++++++++$$$$+++++++++++++++++++++++++++++++++++++++++++$$$$$$
$+++++++$+++++++$$+++++++++++++$$$$+++++++++++++++++++++++++++++++++++++++++$$++
$++++++++$++++++++$$+++++++++++++++$$$$+++++++++++++++++++++++++++++++++++$$++++
$+++++++++$+++++++++$$+++++++++++++++++$$$$++++++++++++++++++++++++++++$$$++++++
$++++++++++$++++++++++$$+++++++++++++++++++$$$$++++++++++++++++++++++$$+++++++++
$+++++++++++$+++++++++++$$+++++++++++++++++++++$$$$+++++++++++++++$$$+++++++++++
$++++++++++++$++++++++++++$$+++++++++++++++++++++++$$$$+++++++++$$++++++++++++++
$+++++++++++++$+++++++++++++$$+++++++++++++++++++++++++$$$$+++$$++++++++++++++++
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
</code></pre>

<p>Lovely!</p>

<p>Now, there is plenty to criticize about this code. It does all kinds of redundant recalculation that in any sane C implementation would have been stashed away into a local, for example. But that&#39;s fixable with a little more effort; I might do another blog post where I apply some of Forth&#39;s fun metaprogramming tricks to that problem.</p>

<p><a href="https://blog.information-superhighway.net/tag:forth" class="hashtag"><span>#</span><span class="p-category">forth</span></a> <a href="https://blog.information-superhighway.net/tag:essays" class="hashtag"><span>#</span><span class="p-category">essays</span></a> <a href="https://blog.information-superhighway.net/tag:code" class="hashtag"><span>#</span><span class="p-category">code</span></a></p>
]]></content:encoded>
      <guid>https://blog.information-superhighway.net/forth-the-local-variable-question</guid>
      <pubDate>Sat, 18 Feb 2023 00:41:54 +0000</pubDate>
    </item>
  </channel>
</rss>