15.6.2.2264 SYNONYM TOOLS EXT

( "<spaces>newname" "<spaces>oldname" -- )

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:

( i * x -- j * x )
Perform the interpretation semantics of oldname.

newname compilation:

( i * x -- j * x )
Perform the compilation semantics of oldname.

See:

Implementation:

The implementation of SYNONYM requires detailed knowledge of the host implementation, which is one reason why it should be standardized. The implementation below is imperfect and specific to VFX Forth, in particular HIDE, REVEAL and IMMEDIATE? are non-standard words.

: SYNONYM \ "newname" "oldname" --
\ Create a new definition which redirects to an existing one.
   CREATE IMMEDIATE
     HIDE ' , REVEAL
   DOES>
     @ STATE @ 0= OVER IMMEDIATE? OR
     IF EXECUTE ELSE COMPILE, THEN
;

ContributeContributions

GerryJacksonavatar of 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.

AntonErtlavatar of AntonErtl

Good point.

Other, less urgent issues are inheritance of TO <name> semantics, and inheritance of the property of being a child of a CREATEd word. Any other issues?

AntonErtlavatar of AntonErtl

Once the "child-of-CREATE" property can be inherited (for >BODY), we need to specify if the following is standard and what it does:

: foo does> drop ." foo" ; : bar does> drop ." bar" ; create a foo synonym b a bar a

We did not standardize using IMMEDIATE on a synonym, should we allow using DOES>?

GerryJacksonavatar of GerryJackson

That's an interesting point. Your example works on my system, as does the following variation:

: foo does> drop ." foo" ;
create a foo
a                         \ Displays foo
: bar does> drop ." bar" ;
synonym a a
a                         \ Displays foo
bar a                     \ Displays bar
foo a                     \ Displays foo

Where bar is defined after a is created. If this usage is deemed standard it provides a way of changing the action of a create ... does> word retrospectively without the need for defer. This is something I have wanted to do in the past. It works on GForth too.

If nothing else ISTM that this could be useful when debugging. For example, during development : could be redefined to generate a create does> drop ... definition. When something goes wrong synonym could be used to alter a word's action to provide debugging information without having to recompile the system. I've not tried it but I don't see in principle why it wouldn't work. So I would support standardising the use of does> for synonyms.

As noted recently on comp.lang.forth is for deferred words also needs to be considered and probably defer@ and defer!.

GerryJacksonavatar of GerryJackson

I was a bit premature with my suggestion - it only works on my system. If my example is amended to include a definition calling a before the use of synonym i.e.

: foo does> drop ." foo" ;
create a foo
: baz a ; baz                        \ Displays foo
: bar does> drop ." bar" ;
synonym a a
bar baz                              \ Displays bar on my system but not on GForth

bar Modifies the behaviour of baz on my system but not GForth or VFX Forth.

In your original example:

: foo does> drop ." foo" ; : bar does> drop ." bar" ; create a foo synonym b a bar a

VFX Forth bar doesn't change the behaviour of a or band so is different compared to Gforth. Win32 Forth is different as it crashes. So four systems with four different behaviours using does> on synonyms.

AntonErtlavatar of AntonErtl

I guess my example works (as in "does not produce an error") in many systems, but what is the effect? Is A changed or is it not? Do we want to standardize one of these behaviours, or not. One reason not to guarantee changing A is that it disallows optimizing DOES>. E.g.,

: method create ... does> ... ;
method draw
: foo ... draw ... ;

Here the compiler can inline DRAW. That's no longer possible if DRAW can be changed later.

Currently only interpretation and compilation semantics is copied by SYNONYM, so the property of being defined by CREATE is not guaranteed to be copied, and the example is non-standard.

Yes, synonyms of DEFERed words is another good point.

Another issue: Consider

wordlist constant W1
wordlist constant W2
W1 set-current create A1
W2 set-current
W1 >order synonym A2 A1
:noname name>string type true ; W2 traverse-wordlist

Will this output A2 or A1? It seems to me that a basic invariant for traverse-wordlist is that, if you SEARCH-WORDLIST for the name produced by NAME>STRING in the traversed wordlist, you will find a word with that name, so it should output A2.

JennyBrienavatar of JennyBrien

If you make a synonym of a word with private data (e.g. a VALUE, a DEFER, or something with CREATE DOES>) then the two words share that data. Any change in the original is reflected in the synonym. If you don't want that, then instead you create a new instance with the same defining word.

So, if that is what you want, do you also need words like TO and IS to be applicable to the synonym as to the original?

That's fairly easy for user-defined definers, I think: All you need do is state that ticking or FINDing a synonym returns the xt of the original. But I think we've already decided not to go that route, and Synonyms may return a different xt from their originals. In any case, the xt of a DEFER or a VALUE is no use for changing the data, so all the Standard data - setting words might have to be modified to allow for the possibility of synonyms.

In short, a Synonym has the same interpretation and compilation behaviour of the original, affecting the same internal data. Any other behaviour that the original may have result from it being defined using a particular defining word, and are not inherited by the synonym.

JennyBrienavatar of JennyBrien

"Will this output A2 or A1? It seems to me that a basic invariant for traverse-wordlist is that, if you SEARCH-WORDLIST for the name produced by NAME>STRING in the traversed wordlist, you will find a word with that name, so it should output A2."

Of course. A synonym may have the same xt as the original, but I don't see how it could have the same name token and still be a different word.

GerryJacksonavatar of GerryJackson

I don't think optimisation should be a significant driver in the functionality of a word - it may help swing the balance in some cases.

What do we mean by synonym? Given synonym B A

  1. is B a snapshot or clone of A that then has a future independent of what happens to A or
  2. is B a reference to A so that it shadows whatever happens to A
  3. or something in between.

Cloning is easy and doesn't require the use of synonym so meaning 2 should be the desired aim.

We have identified issues with values, deferred words, children of create ... does> ... words, inheritance of ambiguous conditions, and possibly wordlists.

Dealing with the latter first, I don't see what the issue is in your example - A2 is clearly defined in wordlist W2, the invokation of traverse-wordlist is only looking in W2 so why would anybody argue that A1 whould be displayed?

Putting that aside and considering synonym B A again:

For synonyms of colon definitions, variables and constants it seems clear that if A is later redefined then B still refers to the old definition of A as the alternative would go against Forth tradition.

For values the question is whether to A affects the value of both A and B or A alone. Similarly to B. If we want consistency with variables and constants then to A should change the value of both A and B and that is what I would expect.

The situation with deferred words doesn't seem so clear. It could be argued that if the action of A is changed by is or defer! then that is equivalent to redefinition of A and so should not change the action of B, and vice versa. Alternatively it could be argued that A is not really being redefined, it is more like a variable or value being changed and the change in behaviour is incidental, so both A and B should remain in step. I would favour the latter.

For children of create ... does> it seems to me that the best argument is that after A has been created and there have been later definitions then the action of A cannot be changed by an execution of does>. Defining synonym B A is such a later definition which should, therefore prevent the action of A being changed by does>. My feeling is that we should probably make applying does> to a synonym either ambiguous or forbid it. Changing the action of A could easily lead to obscure bugs in a program. Of course the same could be said for deferred words.

JennyBrienavatar of JennyBrien

For values the question is whether to A affects the value of both A and B or A alone. Similarly to B. If we want consistency with variables and constants then to A should change the value of both A and B and that is what I would expect.

I agree with that, but the question I was asking was rather:

Given Value A Synonym B A Is TO B guaranteed to work?

I think it would naturally for a flag-setting TO but it may fail on some systems with a parsing TO,

Perhaps the most logical way to think of a Synonym is that it creates a header that returns the same values for NAME>INTERPRET and NAME>COMPILE as the original. (I'm not saying this is the only way it can be done, but it is a way that the Standard allows - I think).

These are the only values (apart from the NAME) that a Standard application can derive from the dictionary structure.

They are also set by:

DOES> associates the xt with an action that uses the data space address that it previously returned IMMEDIATE sets the compilation action to execute the xt COMPILES> (or SET-COMPILER whatever else we decide to set a particular non-default compiliation action.)

In each case they can only be set for the current definition, and are invariant once that definition is complete.

Given this a synonym is an exact substitute for the original, with the same Standard behaviour in all situations. For example, if the original can be ticked, then ticking the synonym returns the same xt. If ticking the original is an ambiguous condition, then a Standard program cannot tick the synonym, it may or may not respond in the same fashion as the the original (which may for example have been marked as 'compile-only') but that is beyond the scope of he Standard.

It doesn't seem to make much sense to combine SYNONYM with any of the other behaviour-setting words, because that implies you want something other than a synonym - something that can be provided in other ways:

Synonym B A DOES> C probably wouldn't work, or would change the definition of A, but the intention can be achieved by:

' A >BODY CONSTANT D : B D C ;

Synonym B A IMMEDIATE is trivially : B A ; IMMEDIATE

And these definitions, not being synonyms of the original, do not share its xt.

Where A is defined by a user-defined CREATE …DOES> word (there must be a shorter way of saying that) any word that uses >BODY to manipulate its data will naturally also work on its synonym, which returns the same data and therefore references the same data.

I'm assuming that words manipulate DEFER and the like (which need not use CREATE … DOES>) also access their data solely through their xt and therefore will work for a synonym that return the same xt. It's possible that IS, TO etc. need access to some other information in the dictionary header, so SYNOYNYM would need to be smart enough to build the appropriate header for words defined by each of the Standard defining words.

That's another reason why the definition of SYNONYM is implementation-dependent, but I can't quite believe that any implementation would do things in such a roundabout way.

ruvavatar of ruv

People, don't you think that GitHub/ForthHub is more more convenient for such discussions?

GerryJacksonavatar of GerryJackson

@JennyBrien

For values the question is whether to A affects the value of both A and B or A alone. Similarly to B. If we want consistency with variables and constants then to A should change the value of both A and B and that is what I would expect.

I agree with that, but the question I was asking was rather:

I was responding to Anton's message and hadn't seen yours before I submitted mine. I think we were writing a reply at the same time!

Given Value A Synonym B A Is TO B guaranteed to work?

Yes I think so.

I think it would naturally for a flag-setting TO but it may fail on some systems with a parsing TO,

The standard insists on a parsing to, see the specification for to, so we don't need to consider that.

As regards the rest of your reply I think I agree with much of it. My system, which has detached headers, simply provides the same xt for both B and A for synonym B A so anything that is done to A or B is done to both whether by does> to is or defer!. And that seems reasonable to me although I wouldn't object to does> being forbidden.

Actually I've just thought of another issue that would break my system, I think, and that is if we have the sequence

create A
\ Possibly more definitions etc but no application of DOES> to A
: X  does> ...  ;
synonym B A  X

i.e. A is not a create ... does> word. This may be a good reason for banning does>

@ruv I don't mind where the discussion is held. This site was set up specifically for the Forth 200X standard with a provision for comments, and so it is not unreasonable to have a discussion here.

JennyBrienavatar of JennyBrien

The standard insists on a parsing to, see the specification for to, so we don't need to consider that.

It insists that a parsing TO be allowed - so the name must always follow directly, without another word or line break in between as is possible with a non - parsing TO.

As regards the rest of your reply I think I agree with much of it. My system, which has detached headers, simply provides the same xt for both B and A for synonym B A so anything that is done to A or B is done to both whether by does> to is or defer!. And that seems reasonable to me although I wouldn't object to does> being forbidden.

Actually I've just thought of another issue that would break my system, I think, and that is if we have the sequence

create A
 \ Possibly more definitions etc but no application of DOES> to A
: X  does> ...  ;
synonym B A  X

i.e. A is not a create ... does> word. This may be a good reason for banning does>

Either way, I think what happens here is that both A and B are set to do X. That is definitely a bad idea: the definition of a word (in this case A) should not change after it has been used - unless of course it's a Deferred word, where you state at the outset that that's your intention.

This case is covered. B has not been defined using CREATE, so the code is already non - Standard.

AntonErtlavatar of AntonErtl

On optimization: Stroustroup had a design rule when developing C++: a new language feature should not slow down the implementation of other, previously existing language features; if we follow this rule (and it sounds pretty sensible for a language like Forth), SYNONYM should not slow down the implementation of DOES>.

In particular, the ability to change a CREATEd word later (after having used it or already changed it once with DOES>) is something that is rarely used in Forth, and changing it through a synonym is likely to be used even more rarely; if it is really desired, this functionality can already be achieved with, e.g., DEFERred words. So the ability to change a CREATEd word later through a synonym would cost performance without gaining capability, and, in nearly all cases not even convenience.

[As an aside, this whole issue is another fallout of the design of CREATE...DOES> of having a word first and changing its behaviour later, which also makes problems in connection with flash-based Forth systems and with having an intelligent COMPILE,; a better design would fix the behaviour at creation time, which would avoid all three problems.]

Clone or reference: This plays a role for mutable words like variables, values, and deferred words. It seems to me that the intention is to be a reference; this is already clear for variables (executing the xt must give the same address), but for values and deferred words the specification is not yet specific enough to make that airtight.

However, when it comes to NAME>STRING, we want the synonym to have it's own name and therefore it needs its own nt; that's the issue the A1 A2 example points out. In some systems (especially some that want to have NT=XT) the most straightforward implementation of SYNONYM might produce the same NT for A1 and A2, and then the output of W2 TRAVERSE-WORDLIST might be A1. Implementations of SYNONYM that get this right will either deviate from the NT=XT dogma or will incur some complications when implementing TO, IS, ACTION-OF, DEFER@, DEFER!, and >BODY.

Overall, the consensus for a tightened synonym seems to be:

  • The synonym inherits the properties of being defined by CREATE or DEFER, and any ambiguous conditions about ticking and POSTPONEing from the original.

  • Concerning DOES>, one must not apply that to a synonym, like IMMEDIATE.

  • TO, IS, ACTION-OF, DEFER@, DEFER!, >BODY are allowed on the synonym if they are allowed on the original, and produce the same results for the synonym as for the original.

  • NAME>STRING produces the name of the original for the original, and the name of the synonym for the synonym.

  • 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 I don't think we need to require that; if some system wants to produce different values, what's the harm (apart from the fact that it probably has a more complicated implementation of the words mentioned above)?

Did I forget anything?

Reply New Version

GerryJacksonavatar of GerryJackson [60] Tighten the specification of SYNONYM (version 1)Proposal2018-06-08 10:09:18

This contribution has been moved to the proposal section.

BerndPaysanavatar of BerndPaysan

This reply has been moved to the proposal section.

JennyBrienavatar of JennyBrien

This reply has been moved to the proposal section.

BerndPaysanavatar of BerndPaysan

This reply has been moved to the proposal section.

BerndPaysanavatar of BerndPaysan

This reply has been moved to the proposal section.

GerryJacksonavatar of GerryJackson

This reply has been moved to the proposal section.

GerryJacksonavatar of GerryJackson

This reply has been moved to the proposal section.

AntonErtlavatar of AntonErtl

This reply has been moved to the proposal section.

JennyBrienavatar of JennyBrien

This reply has been moved to the proposal section.

AntonErtlavatar of AntonErtl

This reply has been moved to the proposal section.

JennyBrienavatar of JennyBrien

This reply has been moved to the proposal section.

AntonErtlavatar of AntonErtl

This reply has been moved to the proposal section.

ruvavatar of ruv

This reply has been moved to the proposal section.

ruvavatar of ruv

This reply has been moved to the proposal section.

ruvavatar of ruv

This reply has been moved to the proposal section.

LeonWagneravatar of LeonWagner

This reply has been moved to the proposal section.

LeonWagneravatar of LeonWagner

This reply has been moved to the proposal section.
Formal
Reply New Version

ruvavatar of 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.

Reply New Version

AntonErtlavatar of 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).

ruvavatar of ruv

The standard says nothing about "STATE-smart words" in the normative parts. How can you infer from the standard that the existing reference implementation is broken? It seems for me that this implementation does not violate the specification for SYNONYM word.

AntonErtlavatar of AntonErtl

The committee decided (vote #6, 12Y:0:0) to delete the existing reference implementation and replace it with this rationale text:

The implementation of SYNONYM requires detailed knowledge of the host implementation, which is why it is standardized.

Closed
Reply New Version

AntonErtlavatar of 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.

ruvavatar of ruv

An incorrect test cannot show that an implementation is incorrect.

The following test is incorrect:

t{ 1 2 ' my-+ ]execute[ -> 3 }t

Tick returns an identifier for execution semantics, but according to the specification, execution semantics is not defined for the words that created via SYNONYM. Therefore you try to test undefined behavior.

And even the controversial clause "When interpreting, ' xyz EXECUTE is equivalent to xyz"[1] does not support this test since ]execute[ is not equivalent to EXECUTE.

Also, the result of the following test cannot be forecast from the reference implementation:

t{ : comp-my+ postpone my-+ ; -> }t
t{ : ya-+ [ comp-my+ ] ; -> }t
t{ 1 2 ya-+ -> 3 }t

Since depending on implementation of POSTPONE it can be success or failed. Therefore, this test cannot refute the reference implementation, since in some Forth system (with this reference implementation) this test can be success.


[1] From 6.1.0070. This clause actually represents merely the default interpretation semantics, see 3.4.3.2.

Reply New Version

JamesNorrisavatar of 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.'

AntonErtlavatar of AntonErtl

The part "when looking up oldname, newname shall not be found" is intended to specify what happens during the execution of SYNONYM, not later. I.e., when you define

SYNONYM + +

newname '+' is not visible while finding oldname '+' to determine what newname is a synonym of. I agree that "find" is better than "look up" here (e.g., compare with ":", which makes the defined word not "findable").

In the process of tightening SYNONYM we might also fix this. E.g., one might write:

For both strings skip leading space delimiters. Parse newname and oldname delimited by a space. Find oldname, and use the result in the semantics below. Define newname, with the semantics defined below. Note that newname may be the same as oldname.

This resolves the issue by specifying that oldname is found before newname is defined.

JamesNorrisavatar of JamesNorris

The new way you worded it is a lot clearer to me. thumbs up

JamesNorrisavatar of JamesNorris

The part "For both strings skip leading space delimiters" is extra since the definition of parsing a name already covers this. Someone might wonder what kinds of strings since the word string is not used after oldname and newname. What about just removing "For both strings skip leading space delimiters"?

JamesNorrisavatar of JamesNorris

Just thought of something else. Do the new word name strings and old word name strings have to be on the same line? Like if you are loading from a file? And some implementations have the same execution token while others do not... If not, then something like this might be clearer:

Parse two word name strings newname and oldname. Note that both word name strings may have more than one leading delimiter. Find the oldname in the search order, and get it's semantics (cfa pfa, runtime compiletime behavior... whatever you are calling it?). Define newname with the semantics of old name and add it to the current new word wordlist. Note that newname may be the same as oldname. Note that newname may have a different execution token than old name.

Reply New Version

ruvavatar of 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.

ruvavatar of ruv

One problem with this definition for synonym is that in some cases it produces incorrect synonyms for the words that may change or access the return stack (R-related words), like exit, >r, r@, i, etc.

This definition for synonym assumes that if find returns n value -1 in interpretation sate, then the word is an ordinary word (according to the clarification), and it can be redefined as an ordinary colon-definition.

In some systems find returns n value -1 in interpretation state for some R-related words, but an R-related word cannot be redefined as an ordinary word. E.g, : >r ( x -- ) >r ; is an incorrect re-definition. So this synonym will create an incorrect synonym in such case.

I think, the standard should restrict the systems in such a way that it's impossible for find to return n value -1 in interpretation state for R-related words. But it's another discussion (see also "R-related words definition" sub-thread in comp.lang.forth (google-groups).

So, presently a portable definition for synonym should take into account these circumstances concerning R-related words.

ruvavatar of ruvNew Version: Portable implementation for SYNONYM

Hide differences

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.

Also, this implementation takes into account that in some Forth systems FIND returns n value -1 in interpretation state for some R-related words, and makes a workaround for that.

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-027.


: fix-r-words-maybe< ( "name1 name2 ... nameN" -- ) begin >in @ bl word dup count nip 0= if 2drop exit then ( c-addr-in c-addr-name ) find -1 <> if 2drop else drop ( c-addr-in ) \ redefine only in the case of n=-1 dup >r >in ! : \ : oldname postpone oldname ; immediate r> >in ! postpone postpone postpone ; immediate \ NB: the implementation defined interpretation semanics for a redefined R-related word \ are lost for the sake of a poor POSTPONE implementation. then again ;

fix-r-words-maybe< exit recurse itself fix-r-words-maybe< >r r@ rdrop r> 2>r 2r@ 2rdrop 2r> n>r nr> fix-r-words-maybe< i j unloop leave

[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

: \ start compilation of 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
\ : newname compilation 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

\ : newname compilation 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](https://forth-standard.org/proposals/tighten-the-specification-of-synonym-version-1-) 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.

ruvavatar of ruv

I think, the standard should restrict the systems in such a way that it's impossible for find to return n value -1 in interpretation state for R-related words.

Actually, in a plausible system some R-related words can be implemented as ordinary words (and then find can always return n value -1 for them). For example, if a separate R-stack is used, and this stack is not connected to the real internal return stack. And then >r can be even redefined as : >r >r ; (as any ordinary word). And it will work in the most cases. But it will not work in some edge cases!

For example, if execute and compile, are redefined as following:

variable _x
: execute dup >r execute r> _x ! ;

: compile, postpone literal postpone execute ;

and a Forth text interpreter that uses this compile, is applied to:

  : foo 1 >r 2 r> ;  t{ t -> 2 1 }t

then, having ordinary >r and r> words, this test case will fail.

Since foo will be equivalent to:

\ <=> ( the code, generated by "compile," )
  : foo  1  ['] >r   execute                     2  ['] r>   execute                 ;
\ <=> ( substitute "execute" by its definition )
  : foo  1  ['] >r   dup >r execute r> _x !      2  ['] r>   dup >r execute r> _x !  ;
\ <=> ( substitute "execute" by the executed word, and eliminate "dup" )
  : foo  1  ['] >r       >r      >r r> _x !      2  ['] r>       >r      r> r> _x !  ;
\ <=> ( eliminate the ">r r>" pairs )
  : foo  1  ['] >r       >r            _x !      2  ['] r>                  r> _x !  ;
\ <=> ( safely move "['] >r" into another place ) 
  : foo  1                             _x !      2  ['] r>        ['] >r >r r> _x !  ;
\ <=> ( eliminate the ">r r>" pair )
  : foo  1                             _x !      2  ['] r>        ['] >r       _x !  ;
\ <=> ( leave only the effects that are visible for a standard program )
  : foo                                          2  ['] r>                           ;
\ <=> 
  : foo 2  ['] r> ;
\ that is not equivalent to "2 >r 1 r>" 

Hence, it's impossible to hold the expected equivalencies and provide ordinary R-related words in the same time.

So a requirement to hold some equivalencies automatically makes impossible such implementation that find returns n value -1 in interpretation state for some R-related word (NB: the words i, j, unloop, leave are also included).

ruvavatar of ruv

Corrections for typos.

Please read:

 : foo 1 >r 2 r> ;  t{ t -> 2 1 }t

as:

 : foo 1 >r 2 r> ;  t{ foo -> 2 1 }t

And read:

\ that is not equivalent to "2 >r 1 r>" 

as:

\ that is not equivalent to "1 >r 2 r>"

AntonErtlavatar of AntonErtl

On behalf of the committee: As decided in this reply:

The implementation of SYNONYM requires detailed knowledge of the host implementation, which is why it [the word, not a reference implementation] is standardized.

Closed
Reply New Version

AntonErtlavatar of 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.

Reply New Version