Recently on forth-standard.org, Jim Peterson asked whether the standards should eventually adopt a new interface ?: to make it easier to conditionally provide a Forth implementation of word, but only if the word does not already have a (likely faster) implementation:
https://forth-standard.org/standard/core/Colon#contribution-397 I see gforth added ?: in November 2024, but with an implementation that merely scans for the next word that is exactly ";", which is no better than [IF] (really [ELSE]) scanning for [THEN] - it is easily confused by things such as: ?: 2DROP \ comment? ; or demo of the problem DROP DROP ; which causes a stack underflow on gforth (because gforth has 2DROP, so it started scanning; the scan skips \ as if it were a normal word, so the text after \ is not a comment, and once the bare ";" in the supposed comment ends the scan, the next word "or" is interpreted with nothing on the stack). Sure, you'd never write replacement code that horrible, but the point is that when you do blind scanning, you CAN'T recognize which words are scanning words, and thus your blind scan is likely to parse differently than if you were letting Forth interpret the line. Jim's post had an interesting idea - he switched to a version that tried to repurpose the definition as :NONAME and then rewind the dictionary; I disagreed with his approach of using ALLOT to roll back HERE as insufficient for rewinding other state (it may work in a trivial implementation), and suggested that he use MARKER instead. But his approach had a cool effect: In gforth: ?: oops if ; *the terminal*:1:11: error: Control structure mismatch ... ?: b if ; ok Note that by scanning until ; without actually compiling, you have lost all ability to identify blatant problems in the replacement definition. But with Jim's approach, even if the word 'b' is already defined, the fact that he still parsed the rest of the definition (and then taught ; to undo the definition) means that all words between ?: and ; are processed the same whether the word ends up being needed or not, so that "?: b if ;" properly identifies Control structure mismatch in the attempted replacement rather than being a no-op merely because "b" happens to already have a definition. But Jim also pointed out that his idea of redirecting things to a :NONAME required special handling of IMMEDIATE; since the decision point of whether to discard the :NONAME happens before the spot where IMMEDIATE can normally appear. That is, his initial proposal had a fragile workaround so that: ?: RDROP POSTPONE R> POSTPONE DROP ; IMMEDIATE would properly make RDROP immediate on a platform where rdrop was not pre-defined, but would ignore the IMMEDIATE on platforms where RDROP already exists and where you really don't want to mark the previous definition before the ?: as immediate (since :NONAME ... ; IMMEDIATE is ambiguous per the standard). Inspired by that, and with help from ruv, I proposed adding [IMMEDIATE] as a way to syntactically avoid the problem, by allowing this instead: ?: RDROP [IMMEDIATE] POSTPONE R> POSTPONE DROP ; so that you are once again back to the situation of only caring about where the ; lives after the ?: https://theforth.net/package/immediate Would gforth be interested in adding [IMMEDIATE] as an extension word? Then Jim went on to demo that someone might want to do: ?: -ROT ( a b c -- c a b ) -ROT -ROT ; Did you spot the problem? He meant to use "ROT ROT" as the replacement; but his typo goes unchecked on a platform where -ROT is already defined; and only causes an Undefined word exception on the very platforms where his replacement matters. So, observe what happens when I do this in gforth: : nop ; defer cleanup ' nop ' cleanup defer! : unknown-word -13 throw ; : ?: >in @ >r ['] parse-name perform find-name 0= if r> >in ! : exit then noname marker latestxt ['] cleanup defer! \ install marker r@ >in ! : postpone unknown-word postpone ; immediate \ hide existing word r> >in ! : \ proceed to parse as normal, ; will clean up ; : ; postpone ; cleanup \ undo ?: if needed, otherwise a nop ['] nop ['] cleanup defer! \ restore nop cleanup ; immediate Now I can do: ?: a ." in a, v1" ; ?: a ." in a, v2" ; a => in a, v1 and more usefully, if I typo: ?: -rot -rot -rot ; *the terminal*:17:9: error: Undefined word ?: -rot >>>-rot<<< -rot ?; the Forth compiler tells me about my problem! However, there's one thing I can't figure out, and that's how to silence: *terminal*:15:4: warning: redefined a *terminal*:13:4: warning: original location *terminal*:15:19: warning: redefined a *terminal*:15:4: warning: original location ok