Digest #185 2022-06-22
Contributions
: 2* 2 * ;
: R@ R> dup >R ;
Replies
My take is that foo
and bar
are equivalent as far as the execution token is concerned. Once you have the execution token, you cannot determine their name or immediacy with standard means. There are systems that allow access to the name and/or immediacy with non-standard means, and these systems will choose to produce different xts for foo
and bar
.
Actually I don't know any system that would produce the same xt for foo
and bar
. The only standard case where I expect that a system may produce the same xt is for a synonym.
But this statement is older than synonyms, so what is it about? A program might want to check for a certain condition by comparing with an xt, and on a system with code deduplication that produces the same xt for definitions that result in the same code, this might not work as intended.
Given the common practice of not having code deduplication, do we want to restrict the statement to synonyms, in order to let programs use the technique outlined above?
My take is that
foo
andbar
are equivalent as far as the execution token is concerned.
So you want to say that the execution semantics of foo
and the execution semantics of bar
are equivalent (the same), and then these execution semantics may be identified by the same execution token.
Actually, it's obvious from the terms definitions: an execution token identifies execution semantics, so the same execution token identifies the same execution semantics. Not so obvious that the same execution semantics may be identified by the different execution tokens.
Concerning 3.1.3.5 — due to its wording ("to have execution token"), it says not about equivalent execution semantics, but about equivalent Forth words (named Forth definitions), and their associated execution tokens (when these tokens can be retrieved by a standard program).
And in my example the words foo
and bar
(that are named Forth definitions) are not equivalent, and then their definitions are not equivalent, and then 3.1.3.5 is not applicable to this case.
If we want 3.1.3.5 be applicable to this case, we should reword it, I think.
For example, we can replace 3.1.3.5 by the following list (1):
- Different Forth definitions may have the same execution token if these definitions define the same execution semantics.
- Different execution tokens may identify the same execution semantics.
- When an execution token can be obtained by a program before the corresponding execution semantics are defined, this token shall be unique among all the available execution tokens at the moment.
But this statement is older than synonyms, so what is it about?
Probably some system-specific alternatives were already known, e.g. alias
or alike. Also, for example, the same execution token can be easy implemented for constants having the same value, for plain synonyms like : foo2 foo1 ;
, for noops like : foo3 ;
and other simple cases when the generated code is identical.
A program might want to check for a certain condition by comparing with an xt, and on a system with code deduplication that produces the same xt for definitions that result in the same code, this might not work as intended.
Yes, I'm also bothered on this regard.
Given the common practice of not having code deduplication, do we want to restrict the statement to synonyms, in order to let programs use the technique outlined above?
In the latter item in the list (1) I suggest the certain cases when the standard requires xt to be unique. At the moment, it covers only noname-definitions. But I'm going to propose a word germ ( -- xt|0 )
that returns xt of the current definition (a definition being compiled, including a quotation). After that all colon-like definitions (colon, noname, quotation) will have a unique xt among each other, and it meets the common practice.
Once you have the execution token, you cannot determine their name or immediacy with standard means.
Yes, since neither name, nor immediacy are properties of an execution token.
But you can find some words this execution token is associated with.
Saying that words are equivalent if their execution semantics are identical is a ghastly mistake. For example IF
is equivalent to THEN
.
Children of CREATE
, VALUE
and VARIABLE
are distinct definitions. At the very least, think of the disambiguation issues.
Saying that words are equivalent if their execution semantics are identical is a ghastly mistake.
Of course, it's obvious. And it would be too easy disprovable by a counterexample. So I don't think Anton meant that.
Usually, in such contexts "equivalence" means operational equivalence (observational equivalence). Formally, two Forth definitions are equivalent if (and only if) no such a program exists (a standard program) that always halts when one definition is used and never halts when another definition is used. In practice, it's usually enough to demonstrate different behavior in some test case.
: R@ R> dup >R ;
This variant is incorrect.
Implementation dependent variants:
: r@ ( -- x ) ( R: x addr -- x addr ) r> r> tuck >r >r ;
: r@ ( -- x ) ( R: x addr -- x addr ) 2r> over >r >r ;
These variants are not standard compliant since they conflicts with 3.2.3.3 Return stack and they will not work on some systems (nevertheless, it's acceptable for reference implementations).
A portable variant (standard compliant):
: r@ postpone r> postpone dup postpone >r ; immediate
: R@ R> dup >R ;
This variant is incorrect.
Well, actually this variant can be used in some systems (i.e., it's implementation dependent too), namely for systems in which nest-sys always takes 0 cells (see initiation semantics for colon and noname) . While the implementation dependent variants provided by me are for systems in which nest-sys always takes 1 cell (majority of Forth systems without an optimizing compiler).
But all variants in which r@
is defined as an ordinary word don't support some expected equivalences. Namely, it means that the compilation semantics for such r@
can be performed by applying execute
to its xt as ['] r@ compile,
, and then the following test case will fail:
: execute >r r@ execute r> drop ;
: compile, postpone literal postpone execute ;
: [execute] execute ; immediate
bl word r@ ' find ] [execute] [ nip -1 = [if]
t{ :noname 123 >r [ ' r@ compile, ] r> drop ; execute -> 123 }t
[else]
.( The test-case is not applicable to this Forth system ) cr
[then]
So I would consider such implementations as incorrect.
As a real life example, Gforth 0.7.9_20220428 fails this testcase.
the compilation semantics for such
r@
can be performed
by applying
execute
to its xt
It's a typo. It should be read as: "by applying compile,
to its xt"