[HN Gopher] Implementing DOES> in Forth, the entire reason I sta...
       ___________________________________________________________________
        
       Implementing DOES> in Forth, the entire reason I started this mess
        
       Author : todsacerdoti
       Score  : 113 points
       Date   : 2025-06-10 01:36 UTC (21 hours ago)
        
 (HTM) web link (boston.conman.org)
 (TXT) w3m dump (boston.conman.org)
        
       | rickcarlino wrote:
       | Similar (but NOT identical) concept in RetroForth I really
       | enjoyed learning about years ago:
       | https://rickcarlino.com/2021/til-how-retroforth-implements-d...
       | 
       | It's nice to see Forth internal deep dives hitting the front
       | page, great article.
        
       | pyinstallwoes wrote:
       | Okay, so what's the significance of it and what's the boon?
       | 
       | Surprised so little public forth's implement it.
        
         | sph wrote:
         | All the most common Forth I know implement CREATE DOES>
         | 
         | What's funny, is that I used to know how it works, now any time
         | I come across these kind of articles I get more and more
         | confused and further away from understanding. It's like reading
         | those convoluted explanations of what a monad is.
        
           | spc476 wrote:
           | It only briefly goes into what it does, this article goes
           | into _how_ it 's done for a particular implementation.
        
           | alexisread wrote:
           | It implements defining words ie. Additional compiler words.
           | 
           | It does this by doing something now, and later (you could
           | read create does> as now later>)
           | 
           | So for
           | 
           | : CONSTANT CREATE , >DOES @ ;
           | 
           | This makes the defining word CONSTANT, which when run (now)
           | compiles the next word
           | 
           | So CONSTANT myvar will compile myvar. Myvar, when run (later)
           | will get it's value and push it to the datastack.
        
         | anthk wrote:
         | Even EForth under Sublex/Muxleq implements it.
        
           | throwaway77699 wrote:
           | TIL https://github.com/howerj/subleq/
           | https://esolangs.org/wiki/Muxleq
        
         | oneearedrabbit wrote:
         | Decades ago, a closure in Forth was especially innovative with
         | DOES>:                 : COUNTER         CREATE ,         DOES>
         | DUP 1 SWAP +! @ ;       0 COUNTER PK       PK .  \ => 1
         | PK .  \ => 2
         | 
         | A semi-equivalent in Javascript is:                 const
         | counter = init => {         let x = init;         return () =>
         | { x += 1; return x; };       };       const pk = counter(0);
         | console.log(pk());  // => 1       console.log(pk());  // => 2
        
       | mikewarot wrote:
       | Long, long ago I wrote a Forth for OS/2 in assembler (mostly out
       | of spite, because I was told you _couldn 't_ write OS/2 programs
       | in assembler, you had to use C++)
       | 
       | I still don't know what DOES> really does... ;-)
        
         | Someone wrote:
         | It's the delimiter between the code that will run when the word
         | is run and the code that gets compiled to be run later.
         | 
         | Typical usage is for the "code that will run immediately" is to
         | store some data, and for the "code that gets compiled to be run
         | later" to use that data.
         | 
         | perhaps the simplest example is CONSTANT, which can be defined
         | like this:                    : CONSTANT ( w "name" -- )
         | CREATE ,          DOES> ( -- w )              @ ;
         | 
         | Here, the "code that will run immediately" is
         | CREATE ,
         | 
         | which a) reads a name from the command line and creates a word
         | with that name, and then takes the top of the stack and stores
         | that directly after the word's definition.
         | 
         | The "code that gets compiled to be run later" is
         | @
         | 
         | which fetches the formerly stored value (taking the address of
         | the formerly created word from the stack)
         | 
         |  _DOES >_ has to do some shenanigans to make that work, but
         | that's an implementation detail, and will be dependent on the
         | particular FORTH being used.
        
           | kazinator wrote:
           | OK, so if we have                 : NAME alpha beta ... psi
           | omega ;
           | 
           | what happens is that at at compile time, a dictionary entry
           | NAME is created, and then the _alpha ... omega_ words are
           | compiled to be run later.
           | 
           | When DOES> is introduced:                 : NAME alpha beta
           | ... DOES> ... psi omega ;
           | 
           | all of the above still holds. We still have a dictionary
           | entry NAME, which denotes all of the words up to the
           | semicolon, including DOES>.
           | 
           | Then, when we execute NAME in a compilation context, because
           | the word sequence contains DOES>, everything to the left of
           | DOES> is specially treated: it is executed immediately in the
           | compilation context and is removed. But that's not all; DOES>
           | doesn't just execute everything to the left and disappear; it
           | leaves something behind: some word which is then combined
           | with the material to the right of DOES> to form the run-time
           | sequence.
           | 
           | In your example, when we run CONSTANT, the part to the left
           | of DOES> fetches a name from the input stream, and creates a
           | word, and then makes the value on the stack the definition.
           | 
           | the accumulation of to-be-run later words is interrupted, and
           | everything before DOES> is done now, at definition time, and
           | removed from the definition.
           | 
           | The CREATE material, when executed, leaves behind a reference
           | to the word denoting the constant. Then DOES> creates a
           | definition for that word, using the remaining material.
           | 
           | Is that more or less it?
        
         | tengwar2 wrote:
         | OS/2: seems an odd thing to say. I used to write in C and MASM,
         | and there were no particular barriers.
        
       | jackdoe wrote:
       | Amazing article!
       | 
       | I hate DOES> I was implementing it well after 1am last night and
       | I hate it, I have this feeling as something gets harder to
       | implement it means its not right, but I know DOES> is right, so
       | its me, I just couldn't implement it well. It was super
       | frustrating. But now I feel better :)
       | 
       | I am new to Forth but it feels like `create does>` has to be
       | replaced with some new construct, I just want word code to
       | operate on its data, but I need to gain more experience to find
       | out, for now `create does>` will do.
        
         | alexisread wrote:
         | You can replace it, there are two (nearly 3) forths that
         | replace it:
         | 
         | https://github.com/dan4thewin/FreeForth2/blob/master/ff.asm
         | 
         | which uses a double loop to lookup first macro words, and then
         | immediate words
         | 
         | https://github.com/ablevm/able-forth/blob/current/forth.scr
         | 
         | Ableforth implements a defer/expand operation \ to effectively
         | quote words. The basic loop is then simply parse a text word,
         | look it up and execute it.
         | 
         | Both make use of macros (code generators) to implement deferred
         | behaviour, as well as code inlining. Ultimately all these
         | operations implement defer by manipulating the execution flow,
         | something that algebraic effects also do.
         | 
         | I have a feeling that algebraic effects can be used in a Forth
         | to implement DOES.
        
           | retransmitfrom wrote:
           | Two forths is one half.
        
           | astrobe_ wrote:
           | Also Chuck Moore's ColorForth doesn't have "create does>" at
           | all. Probably he considered the complexity was not worth it.
           | I don't have it in my interpreter either, and I don't miss
           | it; for the few near-misses I just use regular literals and
           | calls. For instance, for the textbook example of "self-
           | indexing arrays":                   : index-array swap cells
           | + ;         create a1 10 cells allot         create a2 20
           | cells allot         : array1 a1 index-array ;         :
           | array2 a2 index-array ;
           | 
           | I used to use the "implementation-dependent" trick of popping
           | the return address (in e.g. index-array) to get the data.
           | Less verbose, a bit more efficient. But my implementation
           | doesn't permit it anymore.
           | 
           | Recently I've found out that implementing "self/this" pseudo-
           | value and pseudo-method calls much more useful. The relation
           | with this and "create does>" is that latter can be seen as
           | poor man's closure, or poor man's object [1].
           | 
           | [1] https://stackoverflow.com/questions/2497801/closures-are-
           | poo...
        
         | vdupras wrote:
         | In Dusk OS, I implement does> but with one level of indirection
         | removed. Rather than using create, you bind any number to a
         | behavior. Example:
         | 
         | : foo 1+ does> . ;
         | 
         | 42 foo bar
         | 
         | bar \ prints 43
         | 
         | If you want, you can add the "traditional" indirection in the
         | initialization part, for a similar effect.
         | 
         | So, not quite the same, but almost, and I think it echoes the
         | intuition you have, which is also mine.
        
           | anthk wrote:
           | I miss decimal output for the stack contents by default (with
           | .S).
        
       | 5- wrote:
       | i've never looked closely at any of this, and it's been a long
       | time since i looked at all.
       | 
       | reading colorforth code and especially commentary
       | (https://github.com/Howerd/colorForth) it seemed that it refines
       | the concept of staging into colours (does> might correspond to
       | cyan?).
       | 
       | hopefully someone more knowledgeable will chime in here!
        
       | rwmj wrote:
       | Jonesforth doesn't implement it because it's complicated and not
       | really necessary to understand the basics. Also it's, _erm_ , an
       | exercise for the reader, and this reader solved it very well ;-)
        
         | xkriva11 wrote:
         | I tried do do it in a 16-bit JonesForth-based implemenetation
         | and it required to rename JonesForth CREATE to CREATEHEAD,
         | implement a primitive DODOES and then define these two words:
         | 
         | : CREATE WORD CREATEHEAD DODOES , 0 , ;
         | 
         | : DOES> IMMEDIATE ['] LIT , HERE @ 6 CELLS + , ['] LATEST , [']
         | @ , ['] >DFA , ['] ! , ['] EXIT
        
       | throwaway81523 wrote:
       | CREATE makes a dictionary entry for a word named by the string
       | you supply in the input stream, whose execution semantics are to
       | push onto the stack the address of the dictionary space following
       | the entry that was just created. That address lives in the
       | variable HERE. Execution semantics for a word means some code
       | invoked when you execute the word. That code in turn is pointed
       | to by an address living in a cell that is part of the dictionary
       | entry.
       | 
       | DOES> overwrites that address so that executing the word, instead
       | of doing the default thing, now runs some different code, namely
       | the code that you supply after the DOES>.
       | 
       | This is something of a kludge because the usual implementation
       | stores something (the default semantics) in that cell when you
       | run CREATE, then later overwrites it when you run DOES. Since
       | lots of Forth targets today are microcontrollers whose code
       | storage is in flash memory, overwriting individual already-
       | written cells in code space is not nice.
       | 
       | Early Forths had <BUILDS ... DOES> instead of CREATE ... DOES> .
       | You can see how the angle brackets originally looked symmetrical
       | but after things changed, the bracket only appeared on DOES> and
       | that may be part of why people find it confusing.
       | 
       | <BUILDS didn't install any default action into the newly created
       | word. It left it uninitialized so it would get filled in when
       | DOES> came along. CREATE DOES> was sort of an optimization since
       | CREATE already existed too, making <BUILDS unnecessary. So they
       | got rid of <BUILDS during standardization back in the
       | minicomputer era where this stuff always generated code in ram
       | (or maybe magnetic core) rather than flash. That optimization in
       | turn has bitten some implementers in the butt. So <BUILDS DOES>
       | has come back into usage among some MCU implementations like
       | FlashForth. FlashForth is pretty nice by the way.
       | 
       | Well I didn't mean to type that much, but I hope it helps.
        
         | kazinator wrote:
         | It would seem like less of a kludge if DOES> precipitated into
         | a deferred context terminated by its own semicolon. So you
         | could just type                 CREATE FOO 42 , DOES> @ ;
         | 
         | into an interpreter to create the constant. Then if placed
         | inside a definition, there would be two semicolons:
         | : CONSTANT CREATE , DOES> @ ; ;
         | 
         | It's an extra nesting which makes it clear you have a
         | definition that makes a definition. You could even put words
         | between the semicolons which just become part of the definition
         | of CONSTANT.
         | 
         | It feels as if this DOES> thing is a kludge that activates
         | within definitions, and kind of "hijacks" the rest of their
         | instructions. Without DOES>, the material after it would be
         | part of the definition of CONSTANT and not part of the
         | definition of the word produced by CREATE. The switcheroo feels
         | hacky.
        
           | throwaway81523 wrote:
           | DOES> is separate from the definition. The compiler just
           | remembers what the most recently defined word was, and DOES>
           | modifies a cell in that word's dictionary entry.
        
       ___________________________________________________________________
       (page generated 2025-06-10 23:01 UTC)