Replies: 10 comments 15 replies
-
|
Note that this has the interesting effect that an initial IMMEDIATE behaves differently depending on whether it is the first word in the body of On the other hand, my personal usage will be along the lines of |
Beta Was this translation helpful? Give feedback.
-
|
Correcting myself: A better formulation of this would be that when neither nop nor immediate are marked immediate, the compilation effect of POSTPONE IMMEDIATE is to append the compilation semantics to nop that will execute the compilation semantics of IMMEDIATE when nop is executed. But the compilation semantics of a word that does not list special compilation semantics is to append things to the current definition at the time of execution. Restated, nop is basically compiled to include |
Beta Was this translation helpful? Give feedback.
-
|
My definitions are 99% one-liners, so "immediate" being at the end is not a problem in any way. I have no desire to put it right after the name of the word. |
Beta Was this translation helpful? Give feedback.
-
[...] Amazing work! But this approach is very fragile. A better way is to define another word false value (shall-be-immediate)
: [immediate] ( -- )
true to (shall-be-immediate)
; immediate
: ; ( colon-sys -- )
postpone ;
(shall-be-immediate) if
false to (shall-be-immediate)
immediate
then
; immediate
\ Optional part, to reset the flag after errors, if any
: : ( "name" -- colon-sys )
false to (shall-be-immediate) :
;
: :noname ( -- xt colon-sys )
false to (shall-be-immediate) :noname
;
Testcase t{ : foo [immediate] ; -> }t
t{ : bar ; -> }t
t{ s" foo" get-current search-wordlist nip -> 1 }t
t{ s" bar" get-current search-wordlist nip -> -1 }t |
Beta Was this translation helpful? Give feedback.
-
|
I'm liking your idea of a new word for less fragility. For example, https://forth-standard.org/standard/core/Colon#reply-1491 pointed out that my original version mishandles ": VALUE create , immediate does> ..." in an implementation where TO sets a flag on how to handle the next word. Fixing that in my version might be done by also wrapping But your idea of a new word completely solves the ambiguity, with less wrapping of other words needed. Looks like I get to rewrite my code along the lines of your suggestion! |
Beta Was this translation helpful? Give feedback.
-
|
Similarly, my original draft of Still this could lead to O(2^N) complexity if there were other post-word modifiers (like compile-only, if it did something system-level, etc.). I maintain that a better option is to just ensure that applying such modifiers like |
Beta Was this translation helpful? Give feedback.
-
Updated version:\ This file is in the public domain. NO WARRANTY.
\ Originally designed by Eric Blake, August 2025,
\ with revisions inspired by ruv.
\ Add the word [IMMEDIATE] which can be used to mark the intent of defining
\ an immediate word sooner than waiting until the closing ;
\ The goal of this file is to permit the following:
\ : name [IMMEDIATE] ... ;
\ as syntax sugar for
\ : name ... ; IMMEDIATE
\ to satisfy the mantra "say what you are doing as soon as you can":
\ https://forth-standard.org/standard/core/IMMEDIATE#reply-313
\ First, note that there is an ambiguity observable between implementations
\ on the following code:
\ : foo ." foo " ;
\ : bar [ immediate ] ." bar " ;
\ where some implementations (gforth, SwitfForth, VFX) mark bar as
\ immediate, and others (iForth) mark foo as immediate.
\ https://forth-standard.org/standard/core/IMMEDIATE#contribution-112
\ Forth-2012 16.3.3 basically states that it is ambiguous if a program
\ modifies the compilation word list during compilation, but the purpose
\ of IMMEDIATE is to change the compilation list by making the latest
\ definition immediate. So, regardless of whether : is required to make
\ the latest definition be the ongoing compilation, actually executing
\ IMMEDIATE before ; triggered ambiguous behavior.
\ At the same time, the standard requires this test to pass:
\ T{ : IW9 CREATE , DOES> @ 2 + IMMEDIATE ; -> }T
\ : FIND-IW BL WORD FIND NIP ; ( -- 0 | 1 | -1 )
\ T{ 222 IW9 IW10 FIND-IW IW10 -> -1 }T \ IW10 is not immediate
\ T{ IW10 FIND-IW IW10 -> 224 1 }T \ IW10 becomes immediate
\ Basically, once the DOES> body is installed into iw10, then any future
\ execution of iw10 invokes IMMEDIATE on whatever happens to be the most
\ recently compiled word. Furthermore, while not explicitly shown in
\ the test, it is worth noting that IW9 was not marked immediate; an
\ implementation where IMMEDIATE is immediate is unlikely to pass this
\ test, and an immediate word [IMMEDIATE] must be sure that actually
\ invoking IMMEDIATE does not happen before ; completes.
\ https://forth-standard.org/standard/testsuite#test:core:IMMEDIATE
\ Furthermore, the fact that IMMEDIATE has traditionally been non-immediate
\ means that there is an existing corpus of code that expects to be able
\ to build meta-programming words, such as:
\ : nop : POSTPONE ; IMMEDIATE ;
\ nop filler
\ which should make filler, rather than nop, be immediate. This file does
\ not change that behavior. Although this file does not declare imm:, it
\ also makes it easy to declare
\ : imm: ( "name" -- colon-sys ) : POSTPONE [IMMEDIATE] ;
\ as a way to write "imm: name" instead of ": name [IMMEDIATE]" for an
\ alternative way to declare intent of defining an immediate macro.
\ Implementations that provide other modifiers that affect the most recent
\ definition, such as compile-only or restrict, should be able to do similar
\ wrappers for those words to declare intent at the name of a definition.
\ Likewise, if you rely on the implementation-defined behavior of CODE or
\ ;CODE, you may want those words to have similar treatment to what this
\ file does for :.
\ Standard forth does not provide an easy interface to see if a given nt or
\ xt is immediate, although several implementations provide a word
\ "immediate?" for that purpose. For debugging the effects of this file,
\ it is possible to write a parsing word that is portable:
\ \g Parsing word to display whether the next word is immediate.
\ [DEFINED] immediate? [IF] : imm ( "word" -- ) ' immediate? . ;
\ [ELSE] : imm BL WORD FIND NIP 1 = . ; [THEN]
\ And implementations that support SEARCH-WORDLIST can avoid the need to parse:
\ t{ S" [IMMEDIATE]" GET-CURRENT SEARCH-WORDLIST NIP 1 = -> TRUE }t
\ Dependencies:
\ Requires the following words from the Core word set
\ ! ( : ; ['] EXECUTE EXIT IF IMMEDIATE POSTPONE SWAP THEN VARIABLE
\ Requires the following words from the Core Extension word set
\ \ TRUE
\ Requires the following words from the Tools Extension word set
\ [DEFINED] [IF] [THEN] [UNDEFINED]
\ Compatibility stuff, inspired by gforth
\ document a word that is ambiguous to use outside of compilation semantics
[UNDEFINED] compile-only [IF] : compile-only ; [THEN]
\ specialized tag to distinguish documentation strings from internal comments
[UNDEFINED] \g [IF] : \g ['] \ EXECUTE ; IMMEDIATE [THEN]
\ convenience for altering the contents of a variable
[UNDEFINED] off [IF] : off 0 SWAP ! ; [THEN]
[UNDEFINED] on [IF] : on TRUE SWAP ! ; [THEN]
\ Implementation
\ Flag set when between : and ;
VARIABLE (defining) (defining) off
\ Flag set when ; needs to perform a delayed IMMEDIATE.
VARIABLE (needs-immediate) (needs-immediate) off
\ Wrap ; to honor (needs-immediate) and clear (defining).
: ; ( C: colon-sys -- )
\g Complete a colon-sys after appending run-time semantics of
\g ( R: nest-sys -- ) to the current definition.
POSTPONE ;
(needs-immediate) @ IF
IMMEDIATE \ uses original non-immediate word
(needs-immediate) off
THEN
(defining) off
; IMMEDIATE compile-only
\ Wrap : to set (defining).
: : ( C: "<spaces>name" -- colon-sys )
\g Begin a colon definition for /name/.
:
(defining) on
(needs-immediate) off \ resest the flag after errors, if any
; IMMEDIATE
\ Provide [IMMEDIATE] which will trigger the effects of IMMEDIATE at the
\ next possible safe moment.
: [IMMEDIATE] ( -- )
\g Make the most recent definition (whether a word currently being
\g defined when between : and ;, or the word most recently defined
\g when after ;) an immediate word. Ambiguous if the current or
\g most recent definition does not have a name, or was defined as
\g a SYNONYM.
(defining) @ IF (needs-immediate) on EXIT THEN \ ; will do the job later
IMMEDIATE \ not currently between : and ;, so safe to do now
; IMMEDIATE
\ Optional: wrap :NONAME to reset the flag after erors, if any. Since
\ IMMEDIATE is ambiguous if used after a :NONAME, [IMMEDIATE] is likewise
\ ambiguous if used within a :NONAME.
[DEFINED] :NONAME [IF]
: :NONAME ( -- xt colon-sys )
\g Create an anonymous colon definition.
:noname
(needs-immediate) off
;
[THEN] |
Beta Was this translation helpful? Give feedback.
-
|
And another revision to explicitly make Source code\ This file is in the public domain. NO WARRANTY.
\ Originally designed by Eric Blake, August 2025,
\ with revisions inspired by ruv.
\ Add the word [IMMEDIATE] which can be used to mark the intent of defining
\ an immediate word sooner than waiting until the closing ;.
\ The goal of this file is to permit the following:
\ : name [IMMEDIATE] ... ;
\ as syntax sugar for
\ : name ... ; IMMEDIATE
\ to satisfy the mantra "say what you are doing as soon as you can":
\ https://forth-standard.org/standard/core/IMMEDIATE#reply-313
\ First, note that there is an ambiguity observable between implementations
\ on the following code:
\ : foo ." foo " ;
\ : bar [ immediate ] ." bar " ;
\ where some implementations (gforth, SwitfForth, VFX) mark bar as
\ immediate, and others (iForth) mark foo as immediate.
\ https://forth-standard.org/standard/core/IMMEDIATE#contribution-112
\ Forth-2012 16.3.3 basically states that it is ambiguous if a program
\ modifies the compilation word list during compilation, but the purpose
\ of IMMEDIATE is to change the compilation list by making the latest
\ definition immediate. So, regardless of whether : is required to make
\ the latest definition be the ongoing compilation, actually executing
\ IMMEDIATE before ; triggered ambiguous behavior.
\ At the same time, the standard requires this test to pass:
\ T{ : IW9 CREATE , DOES> @ 2 + IMMEDIATE ; -> }T
\ : FIND-IW BL WORD FIND NIP ; ( -- 0 | 1 | -1 )
\ T{ 222 IW9 IW10 FIND-IW IW10 -> -1 }T \ IW10 is not immediate
\ T{ IW10 FIND-IW IW10 -> 224 1 }T \ IW10 becomes immediate
\ Basically, once the DOES> body is installed into iw10, then any future
\ execution of iw10 invokes IMMEDIATE on whatever happens to be the most
\ recently compiled word. Furthermore, while not explicitly shown in
\ the test, it is worth noting that IW9 was not marked immediate; an
\ implementation where IMMEDIATE is immediate is unlikely to pass this
\ test, and an immediate word [IMMEDIATE] must be sure that actually
\ invoking IMMEDIATE does not happen before ; completes.
\ https://forth-standard.org/standard/testsuite#test:core:IMMEDIATE
\ Furthermore, the fact that IMMEDIATE has traditionally been non-immediate
\ means that there is an existing corpus of code that expects to be able
\ to build meta-programming words, such as:
\ : nop : POSTPONE ; IMMEDIATE ;
\ nop filler
\ which should make filler, rather than nop, be immediate. This file does
\ not change that behavior. Although this file does not declare imm:, it
\ also makes it easy to declare
\ : imm: ( "name" -- colon-sys ) : POSTPONE [IMMEDIATE] ;
\ as a way to write "imm: name" instead of ": name [IMMEDIATE]" for an
\ alternative way to declare intent of defining an immediate macro.
\ The standard is clear that IMMEDIATE is ambiguous if used when the last
\ definition was via :NONAME or SYNONYM; this file does not remove that
\ ambiguity when there is no current definition (doing so would require
\ wrapping every defining word, which does not scale), so [IMMEDIATE] is
\ likewise ambiguous in those situations. However, this file does ensure
\ that [IMMEDIATE] between :NONAME and ; is well-defined to do nothing.
\ The reason for this is so that it becomes easier to copy and paste a
\ definition body without regards to whether the definition was started
\ by ": name" or ":NONAME".
\ Implementations that provide other modifiers that affect the most recent
\ definition, such as compile-only or restrict, should be able to do similar
\ wrappers for those words to declare intent at the name of a definition.
\ Likewise, if you rely on the implementation-defined behavior of CODE or
\ ;CODE, you may want those words to have similar treatment to what this
\ file does for :.
\ Standard forth does not provide an easy interface to see if a given nt or
\ xt is immediate, although several implementations provide a word
\ "immediate?" for that purpose. For debugging the effects of this file,
\ it is possible to write a parsing word that is portable:
\ \g Parsing word to display whether the next word is immediate.
\ [DEFINED] immediate? [IF] : imm ( "word" -- ) ' immediate? . ;
\ [ELSE] : imm BL WORD FIND NIP 1 = . ; [THEN]
\ And implementations that support SEARCH-WORDLIST can avoid the need to parse:
\ t{ S" [IMMEDIATE]" GET-CURRENT SEARCH-WORDLIST NIP 1 = -> TRUE }t
\ Dependencies:
\ Requires the following words from the Core word set
\ ! ( : ; ['] 0< ?DUP EXECUTE EXIT IF IMMEDIATE POSTPONE SWAP THEN VARIABLE
\ Requires the following words from the Core Extension word set
\ \ TRUE
\ Requires the following words from the Tools Extension word set
\ [DEFINED] [IF] [THEN] [UNDEFINED]
\ Compatibility stuff, inspired by gforth
\ document a word that is ambiguous to use outside of compilation semantics
[UNDEFINED] compile-only [IF] : compile-only ; [THEN]
\ specialized tag to distinguish documentation strings from internal comments
[UNDEFINED] \g [IF] : \g ['] \ EXECUTE ; IMMEDIATE [THEN]
\ convenience for altering the contents of a variable
[UNDEFINED] off [IF] : off 0 SWAP ! ; [THEN]
[UNDEFINED] on [IF] : on TRUE SWAP ! ; [THEN]
\ Implementation
\ Integer tracking whether there is an ongoing definition body. 1 after
\ :NONAME, -1 after :, and 0 after ;.
VARIABLE (defining) 0 (defining) !
\ Flag set when ; needs to perform a delayed IMMEDIATE.
VARIABLE (needs-immediate) (needs-immediate) off
\ Wrap ; to honor (needs-immediate) and clear (defining).
: ; ( C: colon-sys -- )
\g Complete a colon-sys after appending run-time semantics of
\g ( R: nest-sys -- ) to the current definition.
POSTPONE ;
(needs-immediate) @ IF
IMMEDIATE \ uses original non-immediate word
(needs-immediate) off
THEN
(defining) off
; IMMEDIATE compile-only
\ Wrap : to delay [IMMEDIATE] by setting (defining).
: : ( C: "<spaces>name" -- colon-sys )
\g Begin a colon definition for /name/.
:
-1 (defining) !
(needs-immediate) off \ resest the flag after errors, if any
;
\ Wrap :NONAME to ignore [IMMEDIATE] by setting (defining).
[DEFINED] :NONAME [IF]
: :NONAME ( -- xt colon-sys )
\g Create an anonymous colon definition.
:NONAME
1 (defining) !
(needs-immediate) off \ resest the flag after errors, if any
;
[THEN]
\ Provide [IMMEDIATE] which will trigger the effects of IMMEDIATE at the
\ next possible safe moment.
: [IMMEDIATE] ( -- )
\g Make the most recent definition (whether a word currently being
\g defined when between : and ;, or the word most recently defined
\g when after ;) an immediate word. Ignored during the body of
\g :NONAME, otherwise ambiguous if the most recent definition does not
\g have a name, or was defined as a SYNONYM.
(defining) @ ?DUP IF \ inside : or :NONAME
0< IF (needs-immediate) on THEN \ delay during :, ignore during :NONAME
EXIT THEN
IMMEDIATE \ not currently defining, so safe to do now
; IMMEDIATE |
Beta Was this translation helpful? Give feedback.
-
|
Now uploaded to https://theforth.net/package/immediate |
Beta Was this translation helpful? Give feedback.
-
|
From /intcode/hence/immediate/README.md:
BTW, if we want to allow testing a definition body interactively (in REPL), |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
My introduction to Forth was Jonesforth, which includes this gem:
But reading the standard, portable programs MUST use the latter spelling, where the notion of whether a word will be immediate can be rather distant from the name of the word itself. And I'm not the only one wondering why you can't portably use immediate closer to the word name: JennyBrien observed "I used to do that very thing many years ago, on the basis of 'say what you are doing as soon as you can'. It's a nice thing to have, and I'm not sure why iForth doesn't allow it."
Further inspired by a demo on how to implement a
?:that avoids redefining a word if it already exists (by swapping over to a:NONAMEthen using negativeALLOTduring ; to undo the extra definition, but which also must special-caseIMMEDIATEsince that word is ambiguous after a:NONAME), I wanted to see if I could solve the ambiguity in a different way.With that introduction, here's my attempt.
Beta Was this translation helpful? Give feedback.
All reactions