DOER

From RevaWiki

Jump to: navigation, search

A DOER is a vectorized word. That means you can change the behaviour of the word on runtime. Here is a simple implementation for Reva (not optimized for speed):

: nop      ;
: ahead    $e9 1, 0 , here ;
: then>    compiling? if r> compile then ;
: ?literal compiling? if literal, then ;

: doer     create ['] nop dup , , does> @ >r ;
: (make)   r> dup 9 + over @ ! cell+ >r ;
macro
: ;then    p: ;; p: then ;
: make     compiling? if p: (make) ' 5 + , ahead
           ;then p: :: ' 5 + 2dup ! cell+ ! ;   
: undo     ' 5 + ?literal then> dup cell+ @ swap ! ;
: like     ' 5 + ?literal then> @ ;
: is       ' 5 + compiling? if literal, then> ! ;then
           2dup cell+ ! ! ;                          

note: "undo" doesn't work for me:

 doer joe
 make joe ." first" ;
 make joe ." second" ;
 make joe ." third" ;
 joe
 undo joe
 joe

prints "third" both times. ron 09:23, 27 March 2006 (PST)

    This is correct behaviour. make makes a difference between to be called inside a colon-definition or to be invoked on toplevel (interpreted). So a better example is
    doer someone
    make someone ." Joe" ;
    : for-mary make someone ." Mary" then ;
    : welcome ." Welcome " someone '! emit ;
    
    welcome
    for-mary welcome
    undo someone
    welcome
    

DOERs do have a default behaviour. You can define this by make or is outside a ":"-definition.



Helmar -- can you please explain what are the advantages of "DOER"s over deferred words? ron 07:53, 27 March 2006 (PST)


The main advantage I see is that it has a default behaviour. Defers dont have this. Eg. you can always do

undo mydoer

to reset the DOER to it's default behaviour. You'll need this if you want to seriously use vectorized words and a word like cold or warm. Otherwise the system could be messed up with unwanted changes to the deferred words or you need to make the default behaviour a "noop" or so, which is eg. not wanted for output words. Helmar 08:01, 27 March 2006 (PST)

Well, defers in Reva always default to noop ron 08:30, 27 March 2006 (PST)


In 6.0.4 , doers have been added in a slightly different manner. The word "defer" has the same functionality as "doer" now. The word "doer" does not exist, but the other ancillary words will be functional and similarly named.

Rather than use a "create ... does> ..." version, a "defer" in the new release will be like this:

db 0e9h   ; jmp relative
dd offset ; where to jump
dd offset ; the 'default'

They also have a different class word, "'defer", but that is just to make it easy to figure out that they are defered; it's otherwise the same as "'forth".

The word "is" now works within colon-definitions (it did not in 6.0.3). The other words are a bit tricky, since the "dd offset" is a relative offset and needs to be calculated correctly.


    Ron, why that different class? I dont like this solution. Also it's easier to implement undo if you make the default also a jump. You need something like
    : undo ' 1+ off ;
    
    for the non-macro version only ;) Seriouly take a closer look to the HelFORTH-implementation of DOERs (call it "defer" if you want - that's only a short search/replace for me :) ).

The class is only so that we can tell the word is a deferred word when doing debugging-stuff. Before, the first byte was $bb, but now it's $e9 like any word with only one word in the definition. So that's not a good indication anymore.

I don't understand why undo is any easier if the default is a jump. The version you just posted will not work; the relative jump value is the same in both places, and will be 4 off. Something like this is better (not tested):

: undo ' 1+ dup cell+ @ swap ! ;

My implementation is faster executing than a does>-based one.


    imagine:
    mydeferword:
      jmp near actual_behaviour
      jmp near default_behavioer
    

    If you now do the

    ' mydeferword 1+ off

    the first jump goes to the second. The next "invention" with this is:

    macro
    : vector $E9 1, 0 , ;
    forth
    

    and used it is as:

    : another_kind_of_defer vector ." Hello" ;
    

    Where something like "is" is defined as:

    : is ' 1+ !r ;
    
    for the non-macro version. ("!r" makes the relative calculations needed for jumps and calls - can be re-used to resolve forward-references)

    Retro makes also usage of "vector". Helmar 15:17, 29 March 2006 (PST)

    Ups, probably I forgot something. The implementation of DOERs for Reva I made for Reva with very simple, common and understandable things (eg. does>) - I did not make any efforts to program something that uses all bells and whistles that are possible (this would make things arcane). So when I talk about HelFORTH-implementation, I mean the arcane thing that is in HelFORTH only at the moment. Helmar 16:04, 29 March 2006 (PST)


OK, I see the utility in vector and especially like that it simplifies things. What is your !r like?


The vector words in Retro are currently (9.1-beta) defined as:

macro
: vector $e9 1, 0 , ;
forth
: devector 0 ' 1+ ! ;
loc:
  : change dup >r - 5 - r> 1+ ! ;
  : make   entry x: vector compile x: ;; ;
 :: '? if change ;then make ;
;loc alias is

The additional code in is allows is to create a vectored word with a default definition of the passed xt if the word doesn't exist already.

Charles 20:17, 29 March 2006 (EST)

Personal tools