Proposal: Tighten the specification of SYNONYM (version 1)
This proposal has been moved into this section. Its former address was: /standard/tools/SYNONYM
This page is dedicated to discussing this specific proposal
ContributeContributions
GerryJackson [60] Tighten the specification of SYNONYM (version 1)Proposal2018-06-08 10:09:18
Problem
Since SYNONYM has been incorporated into the Forth 2012 standard a number of use cases have been discussed that can result in different Forth 2012 systems giving different results. Therefore the specification for SYNONYM needs to be tightened to either specify the results of those cases or to make them ambiguous conditions. This RfD addresses those use cases and proposes solutions.
Terminology: in this RfD given this definition: SYNONYM BAR FOO FOO will be referred to as the original word, BAR as the synonym.
The guiding principle in this RfD is one of 'least surprise to the user'. Following use of SYNONYM a reasonable user expectation is that the synonym can be used in exactly the same way as the original word: the functionality and usage of them should be identical, the same operations should be applicable to them and they should have the same restrictions on usage.
Six aspects of the use of SYNONYM have identified that need to be clarified in the standard.
1) Restrictions (ambiguous conditions).
Given SYNONYM NEW-TO TO then ' NEW-TO is not designated an ambiguous condition by the standard whereas ' TO is
This particular example demonstrates that a synonym should inherit all the restrictions placed on the original word.
2) Values (VALUE, 2VALUE and FVALUE)
Given 123 VALUE FOO SYNONYM BAR FOO The view of the current Forth 2012 committee is that: 456 TO BAR is not permitted by the standard. but of course 456 TO FOO is permitted which may or may not result in FOO and BAR containing the same value.
Contrast this with synonyms of variables where storing a new value in a variable can be done on either the original word or the synonym and, in either case, their contents remain identical.
Therefore the guiding principle indicates that it should be legal for TO to be applied to the synonym of a value and that the values of the original word and its synonym should remain in step whichever word is updated using TO.
3) Deferred Words
Given DEFER FOO SYNONYM BAR FOO
As with TO above, writing ( xt ) IS BAR is not allowed whereas ( xt ) IS FOO is permitted and executing FOO is not guaranteed to give the same result as executing BAR
Similarly there are problems with DEFER!, DEFER@ and ACTION-OF ' some-word ' BAR DEFER! ' BAR DEFER@ and ACTION-OF BAR are invalid as BAR was not defined by DEFER
After ' some-word ' FOO DEFER! FOO and BAR are not guaranteed to hold the same xt
The guiding principle indicates it should be legal for IS, DEFER@, DEFER! and ACTION-OF to be applied to the synonym of a deferred word and for the XTs held by the synonym and original deferred word to be kept in step following the use of IS or DEFER! on either the synonym or original deferred word.
4) CREATE and >BODY
Given CREATE FOO SYNONYM BAR FOO should ' FOO >BODY and ' BAR >BODY give the same result?
At present ' BAR >BODY is an ambiguous condition since BAR was not defined directly via CREATE
This violates the guiding principle. Therefore >BODY should work on the synonym and the result should be the same address as for >BODY on the original word.
5) CREATE and DOES>
Given : DOESER DOES> ... ; CREATE FOO (zero or more definitions) SYNONYM BAR FOO DOESER should the use of DOESER be valid and, if so, should it operate on both FOO and BAR?
The current position in the standard is that it is invalid as it violates the rule that DOES> operates on the previous definition which has to have been CREATE'd.
If there are no definitions between CREATE FOO and SYNONYM BAR FOO then in some systems it is possible for DOES> to change the behaviour of both FOO AND BAR. But, in the general case if not impossible, that would cause severe implementation difficulties.
Therefore the guiding principle should be ignored in this case and applying DOES> to a synonym should be an ambiguous condition.
6) NAME>STRING
Given : FOO ... ; SYNONYM BAR FOO
TRAVERSE-WORDLIST will produce a name token for FOO and BAR. What result should NAME>STRING give for the name tokens of FOO and BAR?
In this case it seems clear that applying NAME>STRING on:
- FOO's name token should be "FOO"
- BAR's name token should be "BAR" Any other result would be surprising (remember that FOO and BAR may be in different wordlists)
Solution
Follow the recommendations listed in the Problem section above. See the proposal below.
Remarks
NAME>INTERPRET and NAME>COMPILE: if they produce the same values for the synonym as for the original, the DEFER@ DEFER! >BODY, and probably also TO, IS, ACTION-OF issues fall out for free. But identical xts are not required
SYNONYM is already forbidden on locals due to the prohibition on definitions inside a colon definition. But that could usefully be noted in a rationale.
Some of the proposed changes could be regarded as bad practice e.g. changing the synonym of a deferred word also changes the original word could be regarded as a hidden side effect, but this already possible with synonyms of variables and Forth is a sharp knife ...
Banning DOES> on a synonym of a CREATEd word is similar to banning IMMEDIATE in that both alter the characteristics of the preceding definition.
Reference Implementation
Not applicable - requires detailed knowledge of the system
Test Cases
1 VALUE val
T{ SYNONYM synval val -> }T
T{ val synval -> 1 1 }T
2 TO val
T{ synval -> 2 }T
T{ 3 TO synval -> }T
T{ val synval -> 3 3 }T
\ Similarly for 2VALUE and FVALUE
DEFER def :NONAME 4 ; IS def
T{ SYNONYM syndef def -> }T
T{ def syndef -> 4 4 }T
T{ :NONAME 5 ; IS syndef }T
T{ def syndef -> 5 5 }T
:NONAME 6 ; CONSTANT defxt
T{ defxt ' syndef DEFER! -> }T
T{ def syndef -> 6 6 }T
T{ ' syndef DEFER@ ' def DEFER@ -> defxt DUP }T
T{ ACTION-OF syndef -> defxt }T
CREATE cre
T{ SYNONYM syncre cre -> }T
T{ ' cre >BODY ' syncre >BODY = -> TRUE }T
\ Testing NAME>STRING is complicated by the facts that:
\ - TRAVERSE-WORDLIST is the only way to get a name token
\ - the order of nt's provided by TRAVERSE-WORDLIST is undefined
\ - names may be stored in the dictionary in upper or lower case
\ If anyone can suggest a simpler test please post it
WORDLIST CONSTANT synwl
GET-ORDER synwl SWAP 1+ SET-ORDER DEFINITIONS
CREATE n>s1
SYNONYM syn-n>s1 n>s1
PREVIOUS DEFINITIONS
: >lower ( ch -- ch' )
DUP 'A' 'Z' 1+ WITHIN IF BL OR THEN ;
\ Case independent string comparison
: i$= ( caddr1 u1 caddr2 u2 -- f ) \ f = TRUE if strings are equal
ROT OVER <> IF DROP 2DROP FALSE EXIT THEN
0 ?DO
OVER C@ >lower OVER C@ >lower <>
IF 2DROP FALSE UNLOOP EXIT THEN
CHAR+ SWAP CHAR+
LOOP 2DROP TRUE
;
: get-name ( nt -- caddr u true ) NAME>STRING TRUE ;
: check-names ( caddr1 u1 caddr2 u2 -- f1 f2 )
DUP 4 > IF 2SWAP THEN ( -- "syn-n>s1" "n>s1" )
S" n>s1" i$= >R
S" syn-n>s1" i$= R>
;
T{ ' get-name synwl TRAVERSE-WORDLIST check-names -- TRUE TRUE }T
\ Can't test DOES> on a synonym as there is no portable way to test ambiguous conditions`
Experience
GForth 0.7.9_20171101, VFX Forth 4.72, author's personal system run all test cases Win32 Forth 6.15.04 runs the test cases except for NAME>STRING (not implemented) SwiftForth 3.7.2 hasn't implemented SYNONYM Other systems not tried.
Proposal
In the Forth 2012 Standard document make the following amendments:
Section 15.6.2.2264 SYNONYM
If oldname was created by VALUE, 2VALUE, FVALUE or DEFER then the value held by newname shall be identical to that held by oldname at all times even if TO, IS or DEFER! is applied, as appropriate, to oldname or newname.
If oldname was defined using DEFER then DEFER@ and ACTION-OF applied to oldname shall produce the same xt as DEFER@ and AACTION-OF applied to newname
If oldname was created by CREATE then ' newname >BODY shall result in the same address as that given by ' oldname >BODY.
NAME>STRING shall produce the name of newname/oldname when applied to the name token of newname/oldname respectively.
All ambiguous conditions applicable to oldname shall apply to newname.
An ambiguous condition shall exist if DOES> is applied to newname.
Section 6.2.2295 TO
Amend the end of the Interpretation: and Compilation: paragraphs to read ... if name was not defined by a word with "TO name run time" semantics or the synonym of such a word.
Section 6.2.1725 IS
Amend the end of the Interpretation: and Compilation: paragraphs to read ... if name was not defined by DEFER or the synonym of such a word.
Sections 6.2.1175 DEFER! and 6.2.1177 DEFER@
Amend the end of the first paragraph to read ... word defined by DEFER or the synonym of such a word.
Section 6.2.0698
Amend the end of the Interpretation and Compilation paragraphs to read ... not defined by DEFER or the synonym of such a word, or if ...
Section 6.1.0550 >BODY
Amend the end of the description to read ... defined via CREATE or the synonym of such a word.
ruv [309] A better approach for SYNONYM wordingComment2023-09-22 17:06:27
Rationale
Instead of mentioning SYNONYM
in many other glossary entries, it's better to use another wording, which does not require that.
In some cases, it's better to specify a glossary entry in a more general manner, than mention SYNONYM
in it (see the proposal below).
According to 2.2.3 Parsed-text notation, "name" has the specified meaning when it's mentioned literally as "name" only. So, newname and oldname are not normative. Probably, we can use indexing as for data type symbols in stack diagrams. When an index not a number, it is concatenated via a dot.
We should ensure that system-defined semantics are the same for synonyms.
If the standard defines some semantics, system-defined semantics shall be equivalent to them, so it's enough to mention system-defined semantics.
In some plausible Forth system implementations the execution token for a word
is identical to the name token for this word,
and the execution tokens for the different words are always different. So
SYNONYM
should not require the same execution token (if any) for name.new and name.old.
The part about deferred words is not enough formal.
Examples
A synonym of the word CREATE
creates a word with the data field address due to the same execution semantics as of CREATE
:
synonym mycreate create
mycreate foo 123 ,
A synonym of a word created via performing the execution semantics of CREATE
returns the same data field address due to the same execution semantics as the original word:
synonym bar foo
bar foo = . \ prints -1
Consequently, the execution token for a synonym is associated with the same data field address (if any) as the xt of the original word:
' bar >body ' foo >body = . \ prints -1
A synonym of a word created via performing the execution semantics of VALUE
returns the same value due to the same execution semantics as the original word:
1 value x
synonym y x
x y = . \ prints -1
Applying TO
to a synonym of a word created via performing the execution semantics of VALUE
changes the value assigned to the original word due to the same TO name
Run-time semantics:
2 to y
x y = . \ prints -1
Proposal (draft)
Re data-field address
In
6.1.0550 >BODY
,
6.1.1250 DOES>
,
Replace the phrase:
defined via
CREATE
by the phrase:
defined via performing
CREATE
execution semantics
Replace the phrase:
defined with
CREATE
or a user-defined word that callsCREATE
.
by the phrase:
defined via performing
CREATE
execution semantics
Re deferred words
In
6.2.1725 IS
,
6.2.0698 ACTION-OF
,
6.2.1177 DEFER@
,
6.2.1175 DEFER!
,
Replace the phrase:
defined by
DEFER
by the phrase:
defined via performing
DEFER
execution semantics
Re SYNONYM
Replace the whole normative part of the glossary entry 15.6.2.2264 SYNONYM
by the following paragraphs:
( "<spaces>name.new" "<spaces>name.old" -- )
Skip leading space delimiters, parse name.new delimited by a space, skip leading space delimiters, parse name.old delimited by a space.
Find name.old. Create a definition for name.new with the semantics defined below; name.new may be the same as name.old.
The execution token for name.new may differ from the execution token for name.old.
An ambiguous condition exists if name.old is not found or IMMEDIATE
is performed when name.new is the most recent definition.
All the ambiguous conditions that exist when using name.old, also exist when using name.new.
If execution semantics are defined by the system for name.old:
name.new Execution: Perform the execution semantics of name.old.
If interpretation semantics are defined by the system for name.old:
name.new Interpretation: Perform the interpretation semantics for name.old.
If compilation semantics are defined by the system for name.old:
name.new Compilation: Perform the compilation semantics for name.old.
If "TO name.old Run-time" semantics are defined for name.old:
TO name.new Run-time: Perform TO name.old Run-time semantics.
If name.old are defined via performing the execution semantics of DEFER
:
IS name.new
performs IS name.old
ACTION-OF name.new
performs ACTION-OF name.old
Applying DEFER@ to the xt of name.new
performs DEFER@
to the xt of name.old
Applying DEFER!
to the xt of name.new
performs DEFER!
to the xt of name.old