Digest #320 2025-10-11

Contributions

[416] 2025-10-10 14:18:47 EricBlake wrote:

proposal - Standardize the well-known -ROT

Author:

Eric Blake

Change Log:

2025-10-10 Initial proposal

Problem:

When doing stack-heavy manipulation (without locals), it is not uncommon to want to grab a single cell located underneath a cell pair, modify it, and then pull the cell pair back to the top of the stack. Equivalently, this can be viewed as pushing the single cell back under the cell pair, or undoing the effects of rot.

Several proposed example implementations have relied on use of the word -rot, because it is well-known across a number of Forth implementations, only to need correction when it is pointed out that the standard does not yet provide a single-word solution for this desired stack effect.

Solution:

Standardizing -rot will guarantee that library code can use this word if present for "undoing" a rot without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial; therefore the new word can be optional. Note, however, that a native implementation of rot typically needs just 4 register moves (including a temporary); implementing -rot as rot rot would naively require 8 register moves, while a native implementation can easily achieve the same 4-move performance of rot.

The suggested pronunciation "m-rote" matches the package name of the public domain implementation given in theforth.net, where "m" is short for "minus"; however, gforth suggests the pronunciation "not_rote". Keep in mind that the standard already pronounces <> as "not-equals" and 0<> as "zero-not-equals", so I'm reluctant to use the pronunciation "not-" on a word that is spelled with - rather than <>.

Typical use:

The standard itself has already suggested using -rot in NR>.

Other comments on the standard (not yet at the level of formal proposals) have mentioned -rot:

Potential future addition of ?: that can define -rot when it is not present

Potential future addition of 2roll that can implement -rot, 2swap, and 2rot.

Proposal:

Add a new glossary entry:

6.1.____ -ROT "m-rote" CORE-EXT
( x1 x2 x3 -- x3 x1 x2 )

Perform a reverse rotation of the top three stack entries.

Rationale: This operation undoes the effects of `rot`.

Reference implementation:

: -rot ( x1 x2 x3 -- x3 x1 x2 ) rot rot ;

Testing:

t{ 1 2 3 -rot -> 3 1 2 }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)


[417] 2025-10-10 16:02:13 EricBlake wrote:

proposal - Standardize the well-known RDROP

Author:

Eric Blake

Change Log:

2025-10-10 Initial proposal

Problem:

When using the return stack during stack-heavy manipulation (without locals), it is not uncommon to have conditional code that places a value on the return stack for some branches of the code, but does not need that value on the data stack after other branches. While the depth of the return stack must be restored before the end of the current definition, it is desirable to have a single word that can remove an item from the return stack without affecting the data stack, undoing only half of the effect of r>.

Several proposed example implementations have relied on use of the word rdrop, because it is well-known across a number of Forth implementations, only to need correction when it is pointed out that the standard does not yet provide a single-word solution for this desired stack effect.

Solution:

Standardizing rdrop will guarantee that library code can use this word if present for discarding a return stack cell, without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial; therefore the new word can be optional. Note, however, that rdrop shares the characteristic of the other return stack manipulation words where it is not portable to attempt to execute the execution token obtained from ticking the word. Furthermore, a native implementation is likely to be more efficient than the immediate version given in the suggested reference implementation.

This proposal does not include 2drop; if that is desired, I'm open to amending this proposal to add it, as that would be yet another example where a native implementation is likely to be more efficient than a pure-Forth immediate wrapper.

Typical use:

... >r do r@ ... loop rdrop

Several suggested reference implementations elsewhere in the standard have used rdrop:

sm/mod

Potential future addition of non-parsing create

The potential future addition of ?: mentioned rdrop as a particularly vexing case, as the effects of immediate add a wrinkle into conditional definition.

Proposal:

Add a new glossary entry:

6.1.---- rdrop "r-drop" Core-Ext

Interpretation:
Interpretation semantics for this word are undefined.

Execution:
( R: x -- )

Remove x from the return stack.

See: 3.2.3.3 Return stack, 6.1.1260 drop, 6.1.2060 r>

Rationale: This operation may be more efficient than `r> drop`.

(Editor's note: If the entries for >r and friends are changed to list Run-time semantics rather than Execution semantics, then this section will need to do likewise)

Amend this sentence in 3.2.3.3 Return stack:

A program shall not access or discard values on the return stack (using r@, r>, rdrop, 2r@, 2r> or nr>) that it did not place there using >r, 2>r or n>r;

Add cross-references to rdrop in 6.1.1260 drop and 6.1.2060 r>.

Reference implementation:

: rdrop ( R: x -- ) postpone r> postpone drop ; immediate

Testing:

t{ : gr3 >r r@ rdrop ; -> }t
t{ 123 gr3 -> 123 }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)


[418] 2025-10-10 18:32:48 EricBlake wrote:

proposal - Standardize the well-known BOUNDS

Author:

Eric Blake

Change Log:

2025-10-10 Initial proposal

Problem:

When working with strings, it is not uncommon to want to use a do/loop iteration over characters in the string. The word also works with other array types with a different stride length than characters. Several proposed example implementations have relied on use of the word bounds, because it is well-known across a number of Forth implementations.

Solution:

Standardizing bounds will guarantee that library code can use this word if present for converting an addr u pair to proper bounds for a ?do/+loop, without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial with a public domain implementation; therefore the new word can be optional.

This proposal sticks the new word in the String Extension word set; although I'm amenable to the committee placing it in whatever word set makes the most sense.

Typical use:

type bounds ?do ... loop \ iterate over characters of input buffer
... constant arr-len  arr-len cells buffer: arr
arr arr-len cells bounds ?do ... 1 cells +loop \ iterate over cells of arr

(Editor's note: the first line relies on the existing post-2012 change to make 1 chars = 1)

The latest forth21-1.pdf draft already includes two conditional definitions of bounds (namely, E.15.6.2.---- find-name and E.17.6.2.2255 substitute), along with a use of bounds in Appendix F.15.6.2.---- find-name with no prior definition in the rest of the test suite in the draft. The tests for find-name in the draft document are not yet reflected into Gerry's testsuite repository as of v0.15.0, but that may be an intentional difference between testing Forth 2012 vs. Forth-202x.

Proposal:

Add a new glossary entry:

17.6.2.---- bounds String-Ext
( addr.start u -- addr.end addr.start )

Compute loop bounds suitable for `?do` for the array starting at addr.start and covering u addressable units, where addr.end is the first address beyond the array.

See: 6.1.1240 do, 6.2.0620 ?do

Rationale: This is a common factor for computing the bounds of a do/loop iteration over each element of an array.  Before using `bounds` on an array whose elements are larger than an addressable unit, the number of elements must first be scaled by the same amount as will later be passed to `+loop`.

Other edits needed (based on forth21-1.pdf):

In E.15.6.2.---- find-name, delete the lines:

[UNDEFINED] bounds [IF]
: bounds ( addr len -- addr+len addr )
OVER + SWAP
;
[THEN]

In E.17.6.2.2255 substitute, delete the lines:

[UNDEFINED] bounds [IF]
: bounds
\ addr len -- addr+len addr
OVER + SWAP
;
[THEN]

Reference implementation:

: bounds ( addr.start u -- addr.end addr.start ) over + swap ;

Testing:

t{ 2 3 bounds -> 5 2 }t
t{ : bnd1 2>r 0 2r> bounds ?do 1+ loop ; -> }t \ slow computation of string length
t{ 0 0 bnd1 -> 0 }t
t{ s" 123" bnd1 -> 3 }t
t{ : bnd2 bounds ?do i c@ loop ; -> }t \ breaks string into characters, last on top
t{ s" 123" bnd2 -> '1' '2' '3' }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)

Replies

[r1584] 2025-10-09 18:59:28 JimPeterson replies:

referenceImplementation - Example implementation for PICK

But since such a word can be defined using standard words, I don't think there's any point in standardizing it before it's used in practice.

I don't think it will be used in practice much unless it's standardized. This feels like a chicken-egg thing. Also, pick can be defined using standard words, yet it has been standardized, so I don't think that's a good argument.

On my specialized system, I have a form of poke (called place, there), and it is convenient to be able to pick stack values to operate on and then poke the results back in place. This happens in words that have more than two parameters, and is further provoked by my system's inability to implement locals (efficiently). It's also more common in loops, where I need to get the stack back to the way it was at the top of the loop.

I try to avoid using poke when I'm writing higher-level code that I want to be portable, so all the examples where I use poke are very machine-specific, internal definitions.


[r1585] 2025-10-10 06:28:39 ruv replies:

referenceImplementation - Example implementation for PICK

@JimPeterson wrote:

This feels like a chicken-egg thing. Also, pick can be defined using standard words, yet it has been standardized, so I don't think that's a good argument.

If someone researches how many systems provide such a word and prepares a proposal, I will support it.

One argument for including some well-known words in the standard is that this ensures that if a Forth system provides a word with that name, that word has the specified behavior (rather than some system-specific behavior). Therefore, programs can check weather a word is provided by the system and define it if it is missing, or confidently use it if it's already present.


[r1586] 2025-10-10 06:54:08 ruv replies:

comment - Interpretation of the top input parameter of PICK

@EricBlake wrote

your 1 2pick has an interesting single-cell stack effect ( x.a x.b x.c -- x.a x.b x.c x.a x.b ) that is not available from any one single standard word,

Similarly, your 1 2roll has the single-cell stack effect ( x.a x.b x.c -- x.c x.a x.b ) which is the well-known -rot

Nice finding! This makes me think that it is even worth including them into the standard :-)


[r1587] 2025-10-10 14:38:21 JimPeterson replies:

comment - Interpretation of the top input parameter of PICK

I feel like the 2(verb) words have too much mental baggage, like EricBlake says, in implying that it's viewing/treating the stack as a collection of doubles. Would it be better to tend towards calling these words something like (verb)2 or D(verb) in order to avoid this implication?:

PICK2    DPICK
POKE2    DPOKE
ROLL2    DROLL

Or (I hesitate to suggest this route) they could be named PICKPICK, POKEPOKE and ROLLROLL, where 5 PICKPICK is equivalent to 5 PICK 5 PICK, etc. This would confuse the issue, because the stack element being indexed would be the least significant, deeper cell of the double, contrary to the previously proposed stack effect:

: 3PICKPICK ( x5 x4 X3 X2 x1 x0 -- x5 x4 X3 X2 x1 x0 X3 X2 )
  3 PICK 3 PICK
;

: 3POKEPOKE ( X5 X4 x3 x2 x1 x0 -- x1 x0 x3 x2 )
  3 POKE 3 POKE
;

: 3ROLLROLL ( x5 x4 X3 X2 x1 x0 -- x5 x4 x1 x0 X3 X2 )
  3 ROLL 3 ROLL
;

At the least, knowing that this sort of doubling of the operation will take place allows me to mentally count through the stack as single cells and determine what index I need. Unfortunately, it makes the stack effect difficult to document succinctly:

PICKPICK ( xd.0 (u.cnt-1)*x u.cnt -- xd.0 (u.cnt-1)*x xd.0 )

etc. Or maybe the document avoids talking about doubles altogether:

PICKPICK (      xu xu-1 ... x0 u.cnt       --    xu xu-1 ... x0 xu xu-1 )
POKEPOKE ( xu+1 xu xu-1 ... x2 x1 x0 u.cnt -- x1 x0 xu-1 ... x2         )
ROLLROLL ( xu xu-1 xu-2 ... x0 u.cnt       --       xu-2 ... x0 xu xu-1 )

Also, it leads to some degenerate situations when u.cnt is 0:

: example ( x2 x1 X0 -- x2 x1 X0 X0 X0 )
  0 PICK 0 PICK
;

: example ( X2 X1 x0 -- x0 )
  0 POKE 0 POKE
;

Simple reference implementations:

: PICKPICK  dup >r pick r> pick ;
: POKEPOKE  dup >r poke r> poke ;
: ROLLROLL  dup >r roll r> roll ;

Variants that treat the stack as a collection of doubles:

: 2PICK  2* 1+ pickpick ;
: 2POKE  2* 1+ pokepoke ;
: 2ROLL  2* 1+ rollroll ;

[r1588] 2025-10-10 15:14:13 EricBlake replies:

proposal - Standardize the well-known -ROT

Author:

Eric Blake

Change Log:

2025-10-10 Add more suggested changes and additional links, typography fixes

2025-10-10 Initial proposal

Problem:

When doing stack-heavy manipulation (without locals), it is not uncommon to want to grab a single cell located underneath a cell pair, modify it, and then pull the cell pair back to the top of the stack. Equivalently, this can be viewed as pushing the single cell back under the cell pair, or undoing the effects of rot.

Several proposed example implementations have relied on use of the word -rot, because it is well-known across a number of Forth implementations, only to need correction when it is pointed out that the standard does not yet provide a single-word solution for this desired stack effect.

Solution:

Standardizing -rot will guarantee that library code can use this word if present for "undoing" a rot, without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial; therefore the new word can be optional. Note, however, that a native implementation of rot typically needs just 4 register moves (including a temporary); implementing -rot as rot rot would naively require 8 register moves, while a native implementation can easily achieve the same 4-move performance of rot.

The suggested pronunciation "m-rote" matches the package name of the public domain implementation given in theforth.net, where "m" is short for "minus"; however, gforth suggests the pronunciation "not_rote". Keep in mind that the standard already pronounces <> as "not-equals" and 0<> as "zero-not-equals", so I'm reluctant to use the pronunciation "not-" on a word that is spelled with - rather than <>.

Typical use:

The standard itself has already suggested using -rot in NR> (note that the original forth-2012.pdf did not have section E.15.6.2.1940; I did not research which later revision introduced reference implementations).

The proposal to add find-name to the standard utilizes -rot, resulting in the forth21-1.pdf draft including a blurb listing an [undefined] -rot [if] implementation.

Other comments on the standard (not yet at the level of formal proposals) have mentioned -rot:

Potential future addition of ?: that can define -rot when it is not present

Potential future addition of 2roll that can implement -rot, 2swap, and 2rot.

Proposal:

Add a new glossary entry:

6.1.---- -rot "m-rote" Core-Ext
( x1 x2 x3 -- x3 x1 x2 )

Perform a reverse rotation of the top three stack entries.

See: 6.1.2160 rot

Rationale: This operation undoes the effects of `rot`.

In 6.1.2160 rot, add a cross-reference section:

See: 6.1.---- -rot

Other edits needed (based on forth21-1.pdf):

In E.15.6.2.---- find-name, delete the lines:

[UNDEFINED] -rot [IF]
: -rot ( a b c -- c a b )
ROT ROT
;
[THEN]

In E.17.6.2.2255 substitute, delete the lines:

[UNDEFINED] -rot [IF]
: -rot
\ a b c -- c a b
ROT ROT
;
[THEN]

Reference implementation:

: -rot ( x1 x2 x3 -- x3 x1 x2 ) rot rot ;

Testing:

t{ 1 2 3 -rot -> 3 1 2 }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)


[r1589] 2025-10-10 16:11:00 EricBlake replies:

proposal - Standardize the well-known RDROP

Author:

Eric Blake

Change Log:

2025-10-10 typo fixes

2025-10-10 Initial proposal

Problem:

When using the return stack during stack-heavy manipulation (without locals), it is not uncommon to have conditional code that places a value on the return stack for some branches of the code, but does not need that value on the data stack after other branches. While the depth of the return stack must be restored before the end of the current definition, it is desirable to have a single word that can remove an item from the return stack without affecting the data stack, undoing only half of the effect of >r.

Several proposed example implementations have relied on use of the word rdrop, because it is well-known across a number of Forth implementations, only to need correction when it is pointed out that the standard does not yet provide a single-word solution for this desired stack effect.

Solution:

Standardizing rdrop will guarantee that library code can use this word if present for discarding a return stack cell, without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial; therefore the new word can be optional. Note, however, that rdrop shares the characteristic of the other return stack manipulation words where it is not portable to attempt to execute the execution token obtained from ticking the word. Furthermore, a native implementation is likely to be more efficient than the immediate version given in the suggested reference implementation.

This proposal does not include 2rdrop; if that is desired, I'm open to amending this proposal to add it, as that would be yet another example where a native implementation is likely to be more efficient than a pure-Forth immediate wrapper.

Typical use:

... >r do r@ ... loop rdrop

Several suggested reference implementations elsewhere in the standard have used rdrop:

sm/mod

Potential future addition of non-parsing create

The potential future addition of ?: mentioned rdrop as a particularly vexing case, as the effects of immediate add a wrinkle into conditional definition.

Proposal:

Add a new glossary entry:

6.1.---- rdrop "r-drop" Core-Ext

Interpretation:
Interpretation semantics for this word are undefined.

Execution:
( R: x -- )

Remove x from the return stack.

See: 3.2.3.3 Return stack, 6.1.1260 drop, 6.1.2060 r>

Rationale: This operation may be more efficient than `r> drop`.

(Editor's note: If the entries for >r and friends are changed to list Run-time semantics rather than Execution semantics, then this section will need to do likewise)

Amend this sentence in 3.2.3.3 Return stack:

A program shall not access or discard values on the return stack (using r@, r>, rdrop, 2r@, 2r> or nr>) that it did not place there using >r, 2>r or n>r;

Add cross-references to rdrop in 6.1.0580 >r, 6.1.1260 drop, 6.1.2060 r>.

Reference implementation:

: rdrop ( R: x -- ) postpone r> postpone drop ; immediate

Testing:

t{ : gr3 >r r@ rdrop ; -> }t
t{ 123 gr3 -> 123 }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)


[r1590] 2025-10-10 18:32:13 ruv replies:

proposal - Standardize the well-known RDROP

I agree with this proposal. You could also mention the word fdrop as a precedent.

The section "Typical use" should be corrected, because it demonstrate an incorrect use.

See 6.1.1240:

do Run-time: ( S: n1|n2 u1|u2 -- ; R: -- loop-sys )

Also, it says: "Anything already on the return stack becomes unavailable until the loop-control parameters are discarded".


[r1591] 2025-10-10 18:37:28 EricBlake replies:

proposal - Standardize the well-known RDROP

I agree with this proposal. You could also mention the word fdrop as a precedent.

Will do on my next revision.

The section "Typical use" should be corrected, because it demonstrate an incorrect use.

Good catch. Just because i and r@ happen to be the same in my implementation (and probably several others) does not make it universally so. I will probably rewrite this into begin/repeat rather than do/loop to reduce the level of abstraction, and avoid that unfortunate return stack interaction.


[r1592] 2025-10-10 19:09:49 ruv replies:

proposal - Standardize the well-known -ROT

Concerning the name -rot

There is only one historically established standard word (other than "-" itself) whose name begins with a minus sign: "-trailing" .

This word name etymology is: "subtract-trailing-spaces"

  • the part "spaces" is omitted as obvious (therefore "trailing" becomes a nominalized adjective);
  • the verb "to subtract" is represented by the minus sign;

In other known words a leading minus sign also means "to subtract". For example, -trailing-garbage in Forth-2012, -text in Forth-83 Uncontrolled reference words (not a part of the Forth-83 standard word set).

That's why I don't like the name «-rot» for a word that does a reverse rotation.

Other options for naming:

  • unrot, from "unrotate";
  • derot, from "derotate";
  • rev, from "reverse rotate";

Maybe someone can suggest something else?


[r1593] 2025-10-10 19:42:52 EricBlake replies:

proposal - Standardize the well-known BOUNDS

Author:

Eric Blake

Change Log:

2025-10-10 typo fixes

2025-10-10 Initial proposal

Problem:

When working with strings, it is not uncommon to want to use a do/loop iteration over characters in the string. With care, the word also works with other array types with a different stride length than characters. Several proposed example implementations have relied on use of the word bounds, because it is well-known across a number of Forth implementations.

Solution:

Standardizing bounds will guarantee that library code can use this word if present for converting an addr u pair to proper bounds for a ?do/+loop, without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial with a public domain implementation; therefore the new word can be optional.

This proposal sticks the new word in the String Extension word set; although I'm amenable to the committee placing it in whatever word set makes the most sense.

Typical use:

source bounds ?do i c@ ... loop \ iterate over characters of input buffer
... constant arr-len  arr-len cells buffer: arr
arr arr-len cells bounds ?do i @ ... 1 cells +loop \ iterate over cells of arr

(Editor's note: the first line relies on the existing post-2012 change to make 1 chars = 1)

The latest forth21-1.pdf draft already includes two conditional definitions of bounds (namely, E.15.6.2.---- find-name and E.17.6.2.2255 substitute), along with a use of bounds in Appendix F.15.6.2.---- find-name with no prior definition in the rest of the test suite in the draft. The tests for find-name in the draft document are not yet reflected into Gerry's testsuite repository as of v0.15.0, but that may be an intentional difference between testing Forth 2012 vs. Forth-202x.

Proposal:

Add a new glossary entry:

17.6.2.---- bounds String-Ext
( addr.start u -- addr.end addr.start )

Compute loop bounds suitable for `?do` for the array starting at addr.start and covering u addressable units, where addr.end is the first address beyond the array.

See: 6.1.1240 do, 6.2.0620 ?do

Rationale: This is a common factor for computing the bounds of a do/loop iteration over each element of an array.  Before using `bounds` on an array whose elements are larger than an addressable unit, the number of elements must first be scaled by the same amount as will later be passed to `+loop`.

Other edits needed (based on forth21-1.pdf):

In E.15.6.2.---- find-name, delete the lines:

[UNDEFINED] bounds [IF]
: bounds ( addr len -- addr+len addr )
OVER + SWAP
;
[THEN]

In E.17.6.2.2255 substitute, delete the lines:

[UNDEFINED] bounds [IF]
: bounds
\ addr len -- addr+len addr
OVER + SWAP
;
[THEN]

Reference implementation:

: bounds ( addr.start u -- addr.end addr.start ) over + swap ;

Testing:

t{ 2 3 bounds -> 5 2 }t
t{ : bnd1 2>r 0 2r> bounds ?do 1+ loop ; -> }t \ slow computation of string length
t{ 0 0 bnd1 -> 0 }t
t{ s" 123" bnd1 -> 3 }t
t{ : bnd2 bounds ?do i c@ loop ; -> }t \ breaks string into characters, last on top
t{ s" 123" bnd2 -> '1' '2' '3' }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)


[r1594] 2025-10-10 20:02:49 ruv replies:

comment - Interpretation of the top input parameter of PICK

@JimPeterson wrote:

I feel like the 2(verb) words have too much mental baggage, like EricBlake says, in implying that it's viewing/treating the stack as a collection of doubles. Would it be better to tend towards calling these words something like (verb)2 or D(verb)

  • (verb)2 — there are no such precedents in the naming of standard words. In practice, the numbers at the end of a name are used for different implementation/versions for a switchable word (a word created with defer).

  • D(verb) — the prefix D in names means the data type "d" (a double-cell signed number, see Data types), like in d+, d-, d., d=, d0<, dabs, etc.

At the moment, the only way (among the standard words) to say that a word operates on a parameter whose type is xd (an unspecified cell pair, 2*x) is to use the prefix "2" in its name.

I understand that at first glance it might seem like 2pick treats the entire stack as a an array of unspecified cell pairs. But after a little study, the reader should realize that 2 (2*x) in its name refers not to the type of the location of the parameter, but to the type of the parameter itself.

Furthermore, there is no practical justification for having a separate word whose only difference is that it counts the stack items that need to be "skipped" in pairs.

Overall, I'm currently only suggesting the specific API for the words 2pick, 2roll, and 2poke, in case anyone wants to implement them. I'm not proposing standardization at this point. We'll see how many systems implement them.


[r1595] 2025-10-10 21:06:42 EricBlake replies:

proposal - Standardize the well-known -ROT

Other options for naming:

Using rev for this is too short for my tastes. I would rather use rev in the functional programing sense of reversing a list, perhaps as in ( 5 6 7 3 rev -- 7 6 5 ), ( 4 5 6 7 4 rev -- 7 6 5 4 ).

Of the others you suggested, unrot is nicer than derot to my ears as a native English speaker.

I spent some time playing with the idea in Google Gemini, asking if it could think of alternative names. Its first suggestion was unrot; it also suggested b-rot or brot (backwards-rotate). When I pressed Gemini harder to give me a link that uses b-rot, it gave up and pointed me to https://www.forth.org/forth_intro/unrot.htm and gave an excuse that because -rot is so much more common than other spellings, and despite -rot not being a standard word, Gemini could not find references to use of other spellings. Quoting Gemini, "While I learned the concepts and names for many variants of stack operations, my inability to find an existing URL for B-ROT strongly indicates that it is not a public term. It is possible it was used in a private project, a local dialect of Forth, or a closed-source system that is not indexed on the public web.". Then Gemini tried to convince me that Forth-94 had -rot in its optional tools extension word-set (a lie), before conceding that -rot exists in code samples even before Forth-94 existed. At this point, I can't trust whether Gemini is accurate or hallucinating about b-rot.

Gemini did seem to locate a number of URLs to FIGForth and other implementations of ": -rot rot rot ;" with provenance back to the late 70s, even though it could not find evidence of Chuck Moore ever using -rot. Even if we don't like the naming etymology if we were designing from scratch, -rot really does have the most use in existing Forth variations. At some point, we have to decide whether the standards body should be in the business of prescribing new behavior rather than documenting existing behavior.

That said, a page named "unrot" on forth.org vs. the package on theforth.net named "mrot" vs. gforth's pronunciation "not_rot" vs. Jonesforth calling it "nrot" means that even if we do name it -rot, we have to decide what pronunciation we want. And if "unrot" is the most popular pronunciation, how hard would it be to convince implementations like gforth to add unrot as an alias to -rot just for the better etymology?

Less common, I have seen at least one Forth fork that had -roll as the inverse to roll; by your naming, unroll would be a better spelling. However, unroll is a common enough term in compiler optimizations (duplicating the body of a short loop for fewer branches) that it seems like a shame to apply it to the unrelated meaning of "inverse roll". (I actually like your proposal of poke as an inverse to pick; roll requires so much more work than pick that I'm just fine if there is no inverse for roll in the standard)


[r1596] 2025-10-10 21:46:32 EricBlake replies:

proposal - Standardize the well-known RDROP

Author:

Eric Blake

Change Log:

2025-10-10 mention fdrop and cs-drop, fix typical usage

2025-10-10 typo fixes

2025-10-10 Initial proposal

Problem:

When using the return stack during stack-heavy manipulation (without locals), it is not uncommon to have conditional code that places a value on the return stack for some branches of the code, but does not need that value on the data stack after other branches. While the depth of the return stack must be restored before the end of the current definition, it is desirable to have a single word that can remove an item from the return stack without affecting the data stack, undoing only half of the effect of >r.

Several proposed example implementations have relied on use of the word rdrop, because it is well-known across a number of Forth implementations, only to need correction when it is pointed out that the standard does not yet provide a single-word solution for this desired stack effect.

Additionally, the standard already has fdrop even though that can be implemented by f0= drop or similar (a more naive f>s drop risks ambiguous behavior if the value in r was out of integer range), as well as cs-drop recently added to the standard (discarding a dest from the control-flow stack was already possible with an extra then; while discarding an orig was only made possible when the cs-drop proposal enhanced cs-pick to allow duplicating an orig, and previously could only be done by abusing carnal knowledge of how an implementation expresses orig in the control-flow stack). As dropping an item from a stack tends to be a common low-level operation, it makes sense to have rdrop for doing the same with the return stack, and where the naming convention is consistent. (Aside: Whether fdrop and cs-drop affect only the data stack or distinct other stacks depends on whether the implementation merges the floating-point or control-flow stacks with the data stack; however, rdrop only affects the return stack since there is no way to merge the return stack with the data stack.)

Solution:

Standardizing rdrop will guarantee that library code can use this word if present for discarding a return stack cell, without worrying about it having different semantics than what most users have come to expect.

A pure-Forth implementation using other standard words is fairly trivial; therefore the new word can be optional. Note, however, that rdrop shares the characteristic of the other return stack manipulation words where it is not portable to attempt to execute the execution token obtained from ticking the word. Furthermore, a native implementation is likely to be more efficient than the immediate version given in the suggested reference implementation.

This proposal does not include 2rdrop; if that is desired, I'm open to amending this proposal to add it, as that would be yet another example where a native implementation is likely to be more efficient than a pure-Forth immediate wrapper.

Typical use:

... >r begin r@ ... until rdrop

Several suggested reference implementations elsewhere in the standard have used rdrop:

fm/mod

Potential future addition of non-parsing create

The potential future addition of ?: mentioned rdrop as a particularly vexing case, as the effects of immediate add a wrinkle into conditional definition.

Proposal:

Add a new glossary entry:

6.2.---- rdrop "r-drop" Core-Ext

Interpretation:
Interpretation semantics for this word are undefined.

Execution:
( R: x -- )

Remove x from the return stack.

See: 3.2.3.3 Return stack, 6.1.1260 drop, 6.1.2060 r>

Rationale: This operation may be more efficient than `r> drop`.

(Editor's note: If the entries for >r and friends are changed to list Run-time semantics rather than Execution semantics, then this section will need to do likewise)

Amend this sentence in 3.2.3.3 Return stack:

A program shall not access or discard values on the return stack (using r@, r>, rdrop, 2r@, 2r> or nr>) that it did not place there using >r, 2>r or n>r;

Add cross-references to rdrop in 6.1.0580 >r, 6.1.1260 drop, 6.1.2060 r>.

Reference implementation:

: rdrop ( R: x -- ) postpone r> postpone drop ; immediate

Testing:

t{ : gr3 >r r@ rdrop ; -> }t
t{ 123 gr3 -> 123 }t

(Editorial note: Other than in the subject, this proposal uses lower-case naming of all words, on the grounds that other proposals in flight deal with either making future Forth case-insensitive on standard words, or with ensuring the standard words are converted to upper-case in renderings as needed.)