15.6.2.2264 SYNONYM TOOLS EXT
For both strings skip leading space delimiters. Parse newname and oldname delimited by a space. Create a definition for newname with the semantics defined below. Newname may be the same as oldname; when looking up oldname, newname shall not be found.
An ambiguous conditions exists if oldname can not be found or IMMEDIATE is applied to newname.
newname interpretation:
Perform the interpretation semantics of oldname.
newname compilation:
Perform the compilation semantics of oldname.
See:
Implementation:
HIDE
, REVEAL
and
IMMEDIATE?
are non-standard words.
ContributeContributions
GerryJackson [24] Incomplete specification of SYNONYMComment2016-11-22 10:02:04
Shouldn't the synonym of a word inherit the restrictions of the parent word. For example
SYNONYM NEW-TO TO
' NEW-TO \ Is apparently valid because it isn't forbidden whereas
' TO \ Is an ambiguous condition
Also this is not forbidden and would be rather confusing
SYNONYM TO TO
' TO
All that it needs is to add a sentence such as:
All ambiguous conditions applying to oldname, also apply to newname.
GerryJackson [60] Tighten the specification of SYNONYM (version 1)Proposal2018-06-08 10:09:18
ruv [116] Reference implementation and POSTPONEComment2019-09-13 09:53:48
POSTPONE
(and [COMPILE]
) should be tweaked to properly work for the words that are created by SYNONYM
in the reference implementation. Actually, they should use EXECUTE-COMPILING
(see an example in a comment for POSTPONE).
Perhaps the corresponding note should be appended into "Implementation" section.
AntonErtl [119] Reference implementation of SYNONYMSuggested reference implementation2019-10-01 18:34:20
The existing reference implementation is broken (it produces STATE-smart words). Here's a one that works (in recent Gforth snapshots):
: s-to ( val nt -- )
>body @ (to) ;
opt: ( xt -- )
?fold-to >body @ ]] literal (to) [[ ;
: s-defer@ ( xt1 -- xt2 )
>body @ defer@ ;
opt: ( xt -- )
?fold-to >body @ ]] literal defer@ [[ ;
defer synonym-prototype
[: >body @ compile, ;] set-optimizer
[: >body @ name>interpret ;] set->int
[: >body @ name>compile ;] set->comp
' s-to set-to
' s-defer@ set-defer@
: synonym ( "name" "oldname" -- )
``synonym-prototype create-from
?parse-name find-name dup 0= -13 and throw
dup compile-only? if compile-only then
, reveal ;
This implementation obviously uses a lot of system-specific stuff (you can read about that in "The new Gforth Header" in the EuroForth 2019 proceedings), but in general, system-specific stuff is necessary for implementing SYNONYM.
This SYNONYM not only implements inheritance of interpretation and compilation semantics, but almost everything else: That a word can have TO, DEFER@, or DEFER! applied to it, as well as its code generator. Things that a synonym defined with the SYNONYM above does not inherit are the nt (they are necessarily different in order for NAME>STRING to work), and you cannot apply DOES> or any of the SET-... words to the SYNONYM of a word and have it affect the original (for most SET-... words, this produces the expected result, but for DOES> and SET-DOES>, it does not).
AntonErtl [120] Test cases for SYNONYMSuggested Testcase2019-10-01 18:41:26
t{ synonym my-+ + -> }t
t{ 1 2 my-+ -> 3 }t
t{ 1 2 ' my-+ ]execute[ -> 3 }t
t{ : comp-my+ postpone my-+ ; -> }t
t{ : ya-+ [ comp-my+ ] ; -> }t
t{ 1 2 ya-+ -> 3 }t
These test cases fail with the existing reference implementation (showing that this implementation is incorrect), and succeeds with the proposed reference implementation.
JamesNorris [143] Does the wording of the rules imply that if you SYNONYM a word with the same name in the same wordlist and then 'look it up', you will get the old word?Request for clarification2020-07-26 11:22:42
At first glance when I read the sentence, the way it was worded it seemed that you would always find the old word. The sentence is this: 'Newname may be the same as oldname; when looking up oldname, newname shall not be found.' When I first read it, because of the semi colon, I was under the impression that the part of the sentence after the semicolon had something to do with what was said before the semi colon. After thinking about it, I realized that this was probably not your intent. If you changed the order and used a period, it might be a lot clearer. Also, other parts of the standard refer to 'looking up' as 'finding'. Might want to be consistent with terms. So, something like this: 'When finding oldname, newname shall not be found. Newname may be the same as oldname.'
ruv [202] Portable implementation for SYNONYMSuggested reference implementation2021-05-19 13:04:00
The specification for SYNONYM
doesn't require that the execution semantics for newname are the same as for oldname (if the latter are defined). But it looks like just an omission.
So the implementation bellow also guarantees that the execution semantics for newname are to perform the execution semantics for oldname (if they are defined).
This implementation relies on the full-fledged FIND
(according to the proposal).
If POSTPONE
in the system correctly appends the compilation semantics of a user-defined STATE-dependent immediate word, then it correctly works for the words created by this SYNONYM
too. Otherwise the system has the corresponding environmental restriction, and a program should obey to a99-q027.
[undefined] lit, [if]
: lit, ( x -- ) postpone literal ;
[then]
: error-no-interp ( -- ) -14 throw ;
: compilation ( -- flag ) state @ 0<> ;
: synonym ( "\<spaces\>newname" "\<spaces\>oldname" -- )
: \ start the new definition for newname
bl word \ parse oldname
\ find oldname in interpretation state
dup >r postpone [ find ] \ NB: revert compilation state
\ if oldname is not found in interpretation state,
\ then provide a replacement, since it can still be found in compilation state
dup 0= if 2drop ['] error-no-interp 1 then ( xt1 n1 ) ( R: c-addr )
\ if n1=-1, then the word is ordinary, it's the simplest case
\ : newname [xt1] ;
-1 = if compile, postpone ; r> drop exit then ( xt1 )
\ otherwise, find oldname in compilation state (that is the current state)
r> find dup 0= -13 and throw 1 = if \ n1=1 n2=1 ( xt1 xt2 )
\ if xts are the same, the word is immediate, create a wrapper
\ : newname [xt1] ; immediate
2dup = if drop compile, postpone ; immediate exit then
\ otherwise, create an immediate word using both xt-s
\ : newname state @ if [xt2] exit then [xt1] ; immediate
2>r postpone compilation postpone if ( R: xt1 xt2 )
r> compile, postpone exit postpone then
r> compile, postpone ; immediate exit
then \ n1=1 n2=-1 - it could be something like "leave"
\ create a possibly dual-semantics word as
\ : newname state @ if xt2 compile, exit then [xt1] ; immediate
2>r postpone compilation postpone if ( R: xt1 xt2 )
r> lit, postpone compile, postpone exit postpone then
r> compile, postpone ; immediate
;
A side note.
We have a proposal for a more advanced SYNONYM
that also guarantees that newname have the same "TO oldname" run-time semantics, "IS oldname" run-time semantics, "defined by CREATE" property, "defined by DEFER" property, etc, if they have place for oldname.
It's difficult to make all these requirements formally consistent, they produce changes in many other glossary entries of the standard, and it can be difficult to implement them in some Forth systems. So a more simple SYNONYM
could be good enough option at the present time.
AntonErtl [267] Etymology of SYNONYMComment2022-09-07 21:15:16
Victor H. Yngve presented SYNONYM (with the syntax shown here) in Forth Dimensions, Vol. VII No. 3, p. 11-13, September/October 1985. The presented implementation is terrible, however.