6.10.10.7 User-defined compile,

You can also change the implementation of compile, for a word, with

set-optimizer ( xt –  ) gforth-1.0 “set-optimizer”

Changes the current word such that compile,ing it executes xt (with the same stack contents as passed to compile,). Note that compile, must be consistent with execute, so you must use set-optimizer only to install a more efficient implementation of the same behaviour.

opt: ( compilation – colon-sys2 ; run-time – nest-sys  ) gforth-1.0 “opt:”

Starts a nameless colon definition; when it is complete, this colon definition will become the compile, implementation of the latest word (before the opt:).

Note that the resulting compile, must still be equivalent to postpone literal postpone execute, so set-optimizer is useful for efficiency, not for changing the behaviour. There is nothing that prevents you from shooting yourself in the foot, however. You can check whether your uses of set-optimizer are correct by comparing the results when you use it with the results you get when you disable your uses by first defining

: set-optimizer drop ;

As an example of the use of set-optimizer, we can enhance one of the definitions of CONSTANT above as follows.

: CONSTANT ( n "name" -- ; name: -- n )
  create ,
  ['] @ set-does>
  [: >body @ postpone literal ;] set-optimizer
;

The only change is the addition of the set-optimizer line. When you define a constant and compile it:

5 constant five
: foo five ;

the compiled five in foo is now compiled to the literal 5 instead of a generic invocation of five. The quotation has the same stack effect as compile,: ( xt -- ). The passed xt belongs to the compile,d word, i.e., five in the example. In the example the xt is first converted to the body address, then the value 5 at that place is fetched, and that value is compiled with the postpone literal (see Literals).

This use of set-optimizer assumes that the user does not change the value of a constant with, e.g., 6 ' five >body !. While five has been defined with create, that is an implementation detail of CONSTANT, and if you don’t document it, the user must not rely on it. And if you use set-optimizer in a way that assumes that the body does not change (like is done here), you must not document that create is used; and conversely, if you document it, you have to write the compile, implementation such that it can deal with changing bodies.

Another example is a better-optimized variant of the fvalue example above:

: compile-fvalue-to ( xt-value-to -- )
  drop ]] >body f! [[ ;
  
: fvalue-to ( r xt -- )
  >body f! ;
' compile-fvalue-to set-optimizer

: fvalue ( r "name" -- ; name: -- r )
  create f,
  ['] f@ set-does>
  [: >body ]] literal f@ [[ ;] set-optimizer
  ['] fvalue-to set-to ;

5e fvalue foo
: bar foo 1e f+ to foo ;
see bar

Compare the code for bar with the one for the earlier definition. Here we see the optimization of both the code for reading the fvalue (coming from the set-optimizer in fvalue) and for writing the fvalue (coming from the set-optimizer applied to fvalue-to. Because an fvalue can change (unlike a constant), the reading part (inside fvalue) compiles the address and a f@ that is performed at run-time.

For fvalue-to, the compile, implementation basically just compiles the code executed by fvalue inline. The compilation semantics of to compiles the address as literal and then the (to) implementation (i.e., fvalue-to). In this process the >body is optimized away.

In practice Gforth’s fvalue includes a few additional twists, e.g., to support +TO.

Note that the call to set-optimizer has to be performed after the call to set-does> (or does>, because set-does> overwrites the compile, implementation itself.

As we can see in the fvalue-to example, we can also apply set-optimizer to individual words rather than inside a defining word like constant or fvalue. In this case, the xt of the word passed to optimizer is usually unnecessary and is dropped, as in compile-fvalue-to.

The engine gforth-itc uses , for compile, and set-optimizer has no effect there.