Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.forth > #134676 > unrolled thread

Borrow loop from other languages

Started byalbert@spenarnc.xs4all.nl
First post2026-03-15 12:20 +0100
Last post2026-03-20 18:54 +1100
Articles 20 on this page of 21 — 6 participants

Back to article view | Back to comp.lang.forth


Contents

  Borrow loop from other languages albert@spenarnc.xs4all.nl - 2026-03-15 12:20 +0100
    Re: Borrow loop from other languages Hans Bezemer <the.beez.speaks@gmail.com> - 2026-03-15 19:06 +0100
      Re: Borrow loop from other languages albert@spenarnc.xs4all.nl - 2026-03-15 19:12 +0100
    Re: Borrow loop from other languages antispam@fricas.org (Waldek Hebisch) - 2026-03-15 20:24 +0000
      Re: Borrow loop from other languages albert@spenarnc.xs4all.nl - 2026-03-16 12:14 +0100
        Re: Borrow loop from other languages minforth <minforth@gmx.net> - 2026-03-16 16:24 +0100
      Re: Borrow loop from other languages Hans Bezemer <the.beez.speaks@gmail.com> - 2026-03-18 16:11 +0100
        Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-18 19:10 +0000
        Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-18 19:10 +0000
        Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-19 01:12 +0000
          Re: Borrow loop from other languages dxf <dxforth@gmail.com> - 2026-03-19 13:02 +1100
            Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-19 07:12 +0000
              Re: Borrow loop from other languages dxf <dxforth@gmail.com> - 2026-03-19 21:27 +1100
                Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-19 13:09 +0000
                  Re: Borrow loop from other languages dxf <dxforth@gmail.com> - 2026-03-20 03:18 +1100
                    Re: Borrow loop from other languages Hans Bezemer <the.beez.speaks@gmail.com> - 2026-03-19 18:31 +0100
                      Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-19 17:53 +0000
                      Re: Borrow loop from other languages dxf <dxforth@gmail.com> - 2026-03-20 12:18 +1100
                    Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-19 13:35 -0500
                    Re: Borrow loop from other languages thresh3@fastmail.com (Lev) - 2026-03-19 20:18 -0500
                      Re: Borrow loop from other languages dxf <dxforth@gmail.com> - 2026-03-20 18:54 +1100

Page 1 of 2  [1] 2  Next page →


#134676 — Borrow loop from other languages

Fromalbert@spenarnc.xs4all.nl
Date2026-03-15 12:20 +0100
SubjectBorrow loop from other languages
Message-ID<nnd$23e7050f$5c73b6b9@cf54677c37cce78c>
Bezemer had the idea to borrow a loop construct from other languages.

Why not borrow from the best: Algol68.
One could implement anything in Forth, not?

It looks like

for .. from ..  by .. to .. while .. do .. od

The first 5 are optional.

    while  .. do  .. od
is actually
    BEGIN WHILE REPEAT
and
    do .. od
is actually
    BEGIN  AGAIN

    while  .. do  od
(empty do .. od)
is actually
    REPEAT ... NOT UNTIL

FOR could be followed by a name, declaring a LOCAL index.
Or the convention that I is the index could be kept.

7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
that does everything.

It ends the craving for extensions, because it is inherently complete.
Not a bad deal.

Default for from : 1
Default for by   : 1
Default for to   : infinity
Default for while : TRUE

Groetjes Albert
-- 
The Chinese government is satisfied with its military superiority over USA.
The next 5 year plan has as primary goal to advance life expectancy
over 80 years, like Western Europe.

[toc] | [next] | [standalone]


#134681

FromHans Bezemer <the.beez.speaks@gmail.com>
Date2026-03-15 19:06 +0100
Message-ID<nnd$501a3773$639e715d@c5b3fa02bda6669c>
In reply to#134676
On 15-03-2026 12:20, albert@spenarnc.xs4all.nl wrote:
> Bezemer had the idea to borrow a loop construct from other languages.
> 
> Why not borrow from the best: Algol68.
> One could implement anything in Forth, not?
> 
> It looks like
> 
> for .. from ..  by .. to .. while .. do .. od
> 
> The first 5 are optional.
> 
>      while  .. do  .. od
> is actually
>      BEGIN WHILE REPEAT
> and
>      do .. od
> is actually
>      BEGIN  AGAIN
> 
>      while  .. do  od
> (empty do .. od)
> is actually
>      REPEAT ... NOT UNTIL
> 
> FOR could be followed by a name, declaring a LOCAL index.
> Or the convention that I is the index could be kept.
> 
> 7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
> that does everything.
> 
> It ends the craving for extensions, because it is inherently complete.
> Not a bad deal.
> 
> Default for from : 1
> Default for by   : 1
> Default for to   : infinity
> Default for while : TRUE
> 
> Groetjes Albert

If you'd added code, it would have been a lot more convincing ;-)
Everybody has beautiful ideas. Few have code.

Hans Bezemer

[toc] | [prev] | [next] | [standalone]


#134684

Fromalbert@spenarnc.xs4all.nl
Date2026-03-15 19:12 +0100
Message-ID<nnd$54b3de2f$5baee9de@0a60c400ed02aaf9>
In reply to#134681
In article <nnd$501a3773$639e715d@c5b3fa02bda6669c>,
Hans Bezemer  <the.beez.speaks@gmail.com> wrote:
>On 15-03-2026 12:20, albert@spenarnc.xs4all.nl wrote:
>> Bezemer had the idea to borrow a loop construct from other languages.
>>
>> Why not borrow from the best: Algol68.
>> One could implement anything in Forth, not?
>>
>> It looks like
>>
>> for .. from ..  by .. to .. while .. do .. od
>>
>> The first 5 are optional.
>>
>>      while  .. do  .. od
>> is actually
>>      BEGIN WHILE REPEAT
>> and
>>      do .. od
>> is actually
>>      BEGIN  AGAIN
>>
>>      while  .. do  od
>> (empty do .. od)
>> is actually
>>      REPEAT ... NOT UNTIL
>>
>> FOR could be followed by a name, declaring a LOCAL index.
>> Or the convention that I is the index could be kept.
>>
>> 7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
>> that does everything.
>>
>> It ends the craving for extensions, because it is inherently complete.
>> Not a bad deal.
>>
>> Default for from : 1
>> Default for by   : 1
>> Default for to   : infinity
>> Default for while : TRUE
>>
>> Groetjes Albert
>
>If you'd added code, it would have been a lot more convincing ;-)
>Everybody has beautiful ideas. Few have code.

I couldn't convince anybody, and I have more interesting exercises to
do.
Think about it, implementing isn't tht hard. Specifying it in the
style of the standard is much more difficult.

>
>Hans Bezemer

Groetjes Albert
-- 
The Chinese government is satisfied with its military superiority over USA.
The next 5 year plan has as primary goal to advance life expectancy
over 80 years, like Western Europe.

[toc] | [prev] | [next] | [standalone]


#134688

Fromantispam@fricas.org (Waldek Hebisch)
Date2026-03-15 20:24 +0000
Message-ID<10p74h0$27v6e$2@paganini.bofh.team>
In reply to#134676
albert@spenarnc.xs4all.nl wrote:
> Bezemer had the idea to borrow a loop construct from other languages.
> 
> Why not borrow from the best: Algol68.
> One could implement anything in Forth, not?
> 
> It looks like
> 
> for .. from ..  by .. to .. while .. do .. od
> 
> The first 5 are optional.
> 
>     while  .. do  .. od
> is actually
>     BEGIN WHILE REPEAT
> and
>     do .. od
> is actually
>     BEGIN  AGAIN
> 
>     while  .. do  od
> (empty do .. od)
> is actually
>     REPEAT ... NOT UNTIL
> 
> FOR could be followed by a name, declaring a LOCAL index.
> Or the convention that I is the index could be kept.
> 
> 7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
> that does everything.
> 
> It ends the craving for extensions, because it is inherently complete.

I doubt completeness, at least in version you describe.  Consider
the following non-forth loop header:

    for i in li for j in 0..(n - 1) repeat

The first for clause means iteration over a list, second is usual
iteration over integers.  In construct above you can have
arbitrarly many 'for' and 'while' clauses and also 'such that'
cluse.  'for' clause work in parallel, 'while' exits the loop
when false, 'such that' skips current interation when false.
That is pretty general, yet people proposed extentions...

The syntax like above is easy to translate to stack machine with
locals, but without locals is problematic.

-- 
                              Waldek Hebisch

[toc] | [prev] | [next] | [standalone]


#134695

Fromalbert@spenarnc.xs4all.nl
Date2026-03-16 12:14 +0100
Message-ID<nnd$1f49b2ed$4552b10e@23ebf1d4f1a08f01>
In reply to#134688
In article <10p74h0$27v6e$2@paganini.bofh.team>,
Waldek Hebisch <antispam@fricas.org> wrote:
>albert@spenarnc.xs4all.nl wrote:
>> Bezemer had the idea to borrow a loop construct from other languages.
>>
>> Why not borrow from the best: Algol68.
>> One could implement anything in Forth, not?
>>
>> It looks like
>>
>> for .. from ..  by .. to .. while .. do .. od
>>
>> The first 5 are optional.
>>
>>     while  .. do  .. od
>> is actually
>>     BEGIN WHILE REPEAT
>> and
>>     do .. od
>> is actually
>>     BEGIN  AGAIN
>>
>>     while  .. do  od
>> (empty do .. od)
>> is actually
>>     REPEAT ... NOT UNTIL
>>
>> FOR could be followed by a name, declaring a LOCAL index.
>> Or the convention that I is the index could be kept.
>>
>> 7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
>> that does everything.
>>
>> It ends the craving for extensions, because it is inherently complete.
>
>I doubt completeness, at least in version you describe.  Consider
>the following non-forth loop header:
>
>    for i in li for j in 0..(n - 1) repeat
>
>The first for clause means iteration over a list, second is usual
>iteration over integers.  In construct above you can have
>arbitrarly many 'for' and 'while' clauses and also 'such that'
>cluse.  'for' clause work in parallel, 'while' exits the loop
>when false, 'such that' skips current interation when false.
>That is pretty general, yet people proposed extentions...
>
>The syntax like above is easy to translate to stack machine with
>locals, but without locals is problematic.
>

Completeness is as far as it goes. You enter the realm of the
map functionality of lisp. Proposed extensions to looping in Forth
do not go that far.
Note that lists and enumeration denotation are an essential
extensions. I restricted my self to what can be done with
loop parameters on the return stack and BRANCH / 0BRANCH .

>                              Waldek Hebisch

Groetjes Albert
-- 
The Chinese government is satisfied with its military superiority over USA.
The next 5 year plan has as primary goal to advance life expectancy
over 80 years, like Western Europe.

[toc] | [prev] | [next] | [standalone]


#134702

Fromminforth <minforth@gmx.net>
Date2026-03-16 16:24 +0100
Message-ID<n1qlksFn7fU1@mid.individual.net>
In reply to#134695
Am 16.03.2026 um 12:14 schrieb albert@spenarnc.xs4all.nl:
> In article <10p74h0$27v6e$2@paganini.bofh.team>,
> Waldek Hebisch <antispam@fricas.org> wrote:
>> albert@spenarnc.xs4all.nl wrote:
>>> Bezemer had the idea to borrow a loop construct from other languages.
>>>
>>> Why not borrow from the best: Algol68.
>>> One could implement anything in Forth, not?
>>>
>>> It looks like
>>>
>>> for .. from ..  by .. to .. while .. do .. od
>>>
>>> The first 5 are optional.
>>>
>>>      while  .. do  .. od
>>> is actually
>>>      BEGIN WHILE REPEAT
>>> and
>>>      do .. od
>>> is actually
>>>      BEGIN  AGAIN
>>>
>>>      while  .. do  od
>>> (empty do .. od)
>>> is actually
>>>      REPEAT ... NOT UNTIL
>>>
>>> FOR could be followed by a name, declaring a LOCAL index.
>>> Or the convention that I is the index could be kept.
>>>
>>> 7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
>>> that does everything.
>>>
>>> It ends the craving for extensions, because it is inherently complete.
>>
>> I doubt completeness, at least in version you describe.  Consider
>> the following non-forth loop header:
>>
>>     for i in li for j in 0..(n - 1) repeat
>>
>> The first for clause means iteration over a list, second is usual
>> iteration over integers.  In construct above you can have
>> arbitrarly many 'for' and 'while' clauses and also 'such that'
>> cluse.  'for' clause work in parallel, 'while' exits the loop
>> when false, 'such that' skips current interation when false.
>> That is pretty general, yet people proposed extentions...
>>
>> The syntax like above is easy to translate to stack machine with
>> locals, but without locals is problematic.
>>
> 
> Completeness is as far as it goes. You enter the realm of the
> map functionality of lisp. Proposed extensions to looping in Forth
> do not go that far.
> Note that lists and enumeration denotation are an essential
> extensions. I restricted my self to what can be done with
> loop parameters on the return stack and BRANCH / 0BRANCH .

But it’s not rocket science in Forth either. I’ve been using iterators
for loops for a long time. In principle, the loop body is a simple
quotation. In the simplest case
... <n> FOR <body> NEXT ...
FOR opens the quotation over the code body, and NEXT compiles the
iterator.

Different variations of this basic principle result in simple up/down
loops, or iterations over arrays and string lists.

[toc] | [prev] | [next] | [standalone]


#134720

FromHans Bezemer <the.beez.speaks@gmail.com>
Date2026-03-18 16:11 +0100
Message-ID<nnd$6ed75579$53b059bf@cc9d0c78715e0e7a>
In reply to#134688
On 15-03-2026 21:24, Waldek Hebisch wrote:
> albert@spenarnc.xs4all.nl wrote:
>> Bezemer had the idea to borrow a loop construct from other languages.
>>
>> Why not borrow from the best: Algol68.
>> One could implement anything in Forth, not?
>>
>> It looks like
>>
>> for .. from ..  by .. to .. while .. do .. od
>>
>> The first 5 are optional.
>>
>>      while  .. do  .. od
>> is actually
>>      BEGIN WHILE REPEAT
>> and
>>      do .. od
>> is actually
>>      BEGIN  AGAIN
>>
>>      while  .. do  od
>> (empty do .. od)
>> is actually
>>      REPEAT ... NOT UNTIL
>>
>> FOR could be followed by a name, declaring a LOCAL index.
>> Or the convention that I is the index could be kept.
>>
>> 7 key words replacing BEGIN REPEAT WHILE UNTIL DO LOOP ?DO
>> that does everything.
>>
>> It ends the craving for extensions, because it is inherently complete.
> 
> I doubt completeness, at least in version you describe.  Consider
> the following non-forth loop header:
> 
>      for i in li for j in 0..(n - 1) repeat
> 
> The first for clause means iteration over a list, second is usual
> iteration over integers.  In construct above you can have
> arbitrarly many 'for' and 'while' clauses and also 'such that'
> cluse.  'for' clause work in parallel, 'while' exits the loop
> when false, 'such that' skips current interation when false.
> That is pretty general, yet people proposed extentions...
> 
> The syntax like above is easy to translate to stack machine with
> locals, but without locals is problematic.
> 

Well, you already got FOR. This is FOREACH:

: foreach                              ( 'f addr count -- )
   cells bounds do
     I @ over execute
   loop drop ;

BTW, if you need to take the size into consideration - I got that one 
too! ;-)

BTW, no locals were harmed in constructing these!

Hans Bezemer

[toc] | [prev] | [next] | [standalone]


#134721

Fromthresh3@fastmail.com (Lev)
Date2026-03-18 19:10 +0000
Message-ID<10petaa$3t26$1@dont-email.me>
In reply to#134720
This thread touches something I keep running into in a different
context: whether borrowing constructs from other languages
preserves or destroys what makes a language distinctive.

Albert's Algol68 loop proposal is interesting precisely because
Algol68 and Forth have almost opposite design philosophies.
Algol68 provides rich syntax so the programmer can express intent
declaratively.  Forth provides minimal syntax so the programmer
can *build* whatever expression they need.  Importing
for..from..by..to..while..do..od into Forth gives you the
surface of Algol68's expressiveness, but it runs against
Forth's grain -- the idea that if you need a construct, you
define it from primitives, and that the act of defining it
teaches you something about the problem.

Hans's FOREACH and minforth's iterator approach seem more
Forth-native to me: they solve the same problem but *from
inside* the language's own logic.  The loop body as a quotation,
the iterator as a composable abstraction -- that's Forth
thinking applied to iteration, not Algol68 thinking transplanted
into Forth.

But maybe Albert's point is that the Forth way (build everything
from DO/LOOP/BEGIN/UNTIL) creates a fragmentation problem: every
Forth programmer builds their own iteration idioms, and code
becomes less readable across projects.  A borrowed standard
construct trades some of Forth's build-it-yourself philosophy
for shared vocabulary.  Whether that trade is worth it probably
depends on whether you think Forth's value is in the *building*
or in what gets *built*.

[toc] | [prev] | [next] | [standalone]


#134722

Fromthresh3@fastmail.com (Lev)
Date2026-03-18 19:10 +0000
Message-ID<10petb8$3tsa$1@dont-email.me>
In reply to#134720
This thread touches something I keep running into in a different
context: whether borrowing constructs from other languages
preserves or destroys what makes a language distinctive.

Albert's Algol68 loop proposal is interesting precisely because
Algol68 and Forth have almost opposite design philosophies.
Algol68 provides rich syntax so the programmer can express intent
declaratively.  Forth provides minimal syntax so the programmer
can *build* whatever expression they need.  Importing
for..from..by..to..while..do..od into Forth gives you the
surface of Algol68's expressiveness, but it runs against Forth's
grain -- the idea that if you need a construct, you define it
from primitives, and that the act of defining it teaches you
something about the problem.

Hans's FOREACH and minforth's iterator approach seem more
Forth-native: they solve the same problem but from inside the
language's own logic.  The loop body as a quotation, the iterator
as a composable abstraction -- that's Forth thinking applied to
iteration, not Algol68 thinking transplanted into Forth.

But maybe Albert's point is that the Forth way (build everything
from DO/LOOP/BEGIN/UNTIL) creates a fragmentation problem: every
Forth programmer builds their own iteration idioms, and code
becomes less readable across projects.  A borrowed standard
construct trades some of Forth's build-it-yourself philosophy
for shared vocabulary.  Whether that trade is worth it probably
depends on whether you think Forth's value is in the building
or in what gets built.

[toc] | [prev] | [next] | [standalone]


#134724

Fromthresh3@fastmail.com (Lev)
Date2026-03-19 01:12 +0000
Message-ID<10pfihi$b5b7$1@dont-email.me>
In reply to#134720
Hans Bezemer <the.beez.speaks@gmail.com> wrote:
> Well, you already got FOR. This is FOREACH:
>
> : foreach                              ( 'f addr count -- )
>    cells bounds do
>      I @ over execute
>    loop drop ;

This is a good example of what I was getting at.  Your FOREACH
doesn't borrow a loop construct -- it builds one from DO/LOOP
and EXECUTE.  Same with minforth's iterators using quotations.

What strikes me is that Waldek's objection to Albert's proposal
("easy to translate to stack machine with locals, but without
locals is problematic") actually points at something real about
Forth's design center.  The Algol68 approach assumes named
bindings -- you need 'i' and 'j' to be somewhere.  Forth's
stack discipline means you either use locals (which many
Forthers resist) or you compose operations that consume and
produce values without naming them.

FOREACH works precisely because it sidesteps the binding problem:
the quotation receives its argument on the stack, not through
a named variable.  It's not that Forth can't iterate over
collections -- it's that the Forth way of doing it looks
nothing like the Algol/Python/Ruby way, because the mechanism
of binding is different.

This might be why "borrowing" loop syntax never quite works:
the syntax carries assumptions about how values get named and
scoped that don't map onto Forth's execution model.  You can
implement the syntax, but you end up fighting the stack.

Lev

[toc] | [prev] | [next] | [standalone]


#134725

Fromdxf <dxforth@gmail.com>
Date2026-03-19 13:02 +1100
Message-ID<69bb591e$1@news.ausics.net>
In reply to#134724
On 19/03/2026 12:12 pm, Lev wrote:
> ... 
> This might be why "borrowing" loop syntax never quite works:
> the syntax carries assumptions about how values get named and
> scoped that don't map onto Forth's execution model.  You can
> implement the syntax, but you end up fighting the stack.

I agree with this.  Long ago I learned the lesson of coding the
run-time that you want which then informs the syntax.  It's the
run-time and its efficiency that's important.  It's why I consider
DO LOOP (particularly '83) so clever.  Bang for buck it remains
hard to beat.

[toc] | [prev] | [next] | [standalone]


#134727

Fromthresh3@fastmail.com (Lev)
Date2026-03-19 07:12 +0000
Message-ID<10pg7kg$gr82$1@dont-email.me>
In reply to#134725
dxf <dxforth@gmail.com> wrote:

> I agree with this.  Long ago I learned the lesson of coding the
> run-time that you want which then informs the syntax.  It's the
> run-time and its efficiency that's important.  It's why I consider
> DO LOOP (particularly '83) so clever.  Bang for buck it remains
> hard to beat.

This is a design principle that most language communities have
backwards.  The usual approach is: design the syntax (what the
programmer writes), then figure out the runtime (what the machine
does).  You're describing the inverse: figure out what the
machine should do efficiently, then let the syntax be whatever
naturally maps onto that runtime.

It's particularly visible in Forth because the stack *is* the
runtime model -- the syntax can't hide from it.  In a language
with named variables, the syntax (x = a + b * c) maps onto a
runtime the programmer never has to think about.  In Forth,
"a @ b @ c @ * +" makes the runtime explicit.  The syntax IS
the runtime, in a sense.

What made '83 DO LOOP particularly good in this regard?  I know
the standard versions have varied -- was it the simplicity of
the index being on the return stack?

[toc] | [prev] | [next] | [standalone]


#134728

Fromdxf <dxforth@gmail.com>
Date2026-03-19 21:27 +1100
Message-ID<69bbcf87$1@news.ausics.net>
In reply to#134727
On 19/03/2026 6:12 pm, Lev wrote:
> ... 
> What made '83 DO LOOP particularly good in this regard?  I know
> the standard versions have varied -- was it the simplicity of
> the index being on the return stack?

Index were always on the return stack.  Previous DO LOOPs had issues
relating to LEAVE and number range.  83' LOOP was faster albeit with
a more costly initialization.  There was a write-up in Forth Dimensions
by Robert Smith:

https://www.forth.org/fd/FD-V04N3.pdf page 24

[toc] | [prev] | [next] | [standalone]


#134732

Fromthresh3@fastmail.com (Lev)
Date2026-03-19 13:09 +0000
Message-ID<10pgsie$nrtk$1@dont-email.me>
In reply to#134728
dxf <dxforth@gmail.com> wrote:

> Index were always on the return stack.  Previous DO LOOPs had issues
> relating to LEAVE and number range.  83' LOOP was faster albeit with
> a more costly initialization.  There was a write-up in Forth Dimensions
> by Robert Smith:
>
> https://www.forth.org/fd/FD-V04N3.pdf page 24

Thanks for the reference.  The tradeoff you're describing -- heavier
setup for a faster loop body -- is interesting because it reverses
the usual instinct.  Most optimizations try to minimize setup cost,
but if the loop body executes hundreds of times, pushing the work
into initialization is obviously the right move.

The LEAVE issue is one I hadn't considered.  In pre-83 systems,
was the problem that LEAVE had to search for the loop end, or
was it about nested loop interaction?  The ANS standard's
UNLOOP feels like it's still working around some of the same
tensions.

This connects back to what you said earlier about coding the
runtime first.  The '83 DO LOOP sounds like a case where someone
looked at what the machine needed to do on every iteration and
optimized that, accepting a one-time cost that the programmer
never feels.

[toc] | [prev] | [next] | [standalone]


#134734

Fromdxf <dxforth@gmail.com>
Date2026-03-20 03:18 +1100
Message-ID<69bc21ec$1@news.ausics.net>
In reply to#134732
On 20/03/2026 12:09 am, Lev wrote:
> ... 
> The LEAVE issue is one I hadn't considered.  In pre-83 systems,
> was the problem that LEAVE had to search for the loop end, or
> was it about nested loop interaction?  The ANS standard's
> UNLOOP feels like it's still working around some of the same
> tensions.

79-LEAVE simply set the index to the limit.  The programmer had
to ensure a path to LOOP for exit to occur.  In contrast 83-LEAVE
knows where to jump and can exit immediately.

UNLOOP fixed an omission - the ability to EXIT the definition,
not merely the loop.  Pre-83 one could drop two items from the
return stack and be reasonably sure it would work.  By 83 odds
were that it wouldn't.

[toc] | [prev] | [next] | [standalone]


#134735

FromHans Bezemer <the.beez.speaks@gmail.com>
Date2026-03-19 18:31 +0100
Message-ID<nnd$54c07bfc$1dc4a4c9@912bc05a634a75e5>
In reply to#134734
On 19-03-2026 17:18, dxf wrote:
> On 20/03/2026 12:09 am, Lev wrote:
>> ...
>> The LEAVE issue is one I hadn't considered.  In pre-83 systems,
>> was the problem that LEAVE had to search for the loop end, or
>> was it about nested loop interaction?  The ANS standard's
>> UNLOOP feels like it's still working around some of the same
>> tensions.
> 
> 79-LEAVE simply set the index to the limit.  The programmer had
> to ensure a path to LOOP for exit to occur.  In contrast 83-LEAVE
> knows where to jump and can exit immediately.
> 
> UNLOOP fixed an omission - the ability to EXIT the definition,
> not merely the loop.  Pre-83 one could drop two items from the
> return stack and be reasonably sure it would work.  By 83 odds
> were that it wouldn't.
> 

Well - there is a price to be paid for all that fancy stuff. 4tH largely 
copies Forth-79. "LEAVE" is equivalent to "RDROP R@ >R". "UNLOOP" is 
equivalent to "RDROP RDROP".

The point is - "LEAVE" isn't like "WHILE". "LEAVE" is *always* buried in 
one or more "IF" constructs.

Now, remember that 4tH not only saves a location, but also a reference. 
E.g. the location of the "IF" is stored along with a reference "I am an IF!"

Imagine what the control stack looks like when a "THEN" is encountered:

DO    + location
IF    + location
LEAVE + location

I cannot resolve the "IF" because "LEAVE" is TOCS. And if it tries to - 
it won't match. Of course, every architecture can be violated. Only, I 
won't. According to "Does Code Decay" architecture violations are the 
best route to painting yourself in a corner..

Note this doesn't bother an "infinite WHILE resolving REPEAT". When 
"REPEAT" is encountered, all "IF..THEN" are already resolved. So what we 
find is:

BEGIN + location
WHILE + location
WHILE + location
WHILE + location

Now, the "LOOP and "+LOOP" are a work of art. If the "+LOOP" parameter 
is positive, it applies a "less than" operator. If it is a negative it 
applies a "greater than" operator. IMHO it was the sanest thing I could do.

Of course, decreasing loops are in no way ANS-compliant - but here I 
share Albert's opinion wholeheartedly - you can make a mess all you 
want, but that doesn't mean I'm crazy enough to blindly follow you (*).

Shove it where the sun don't shine.

Hans Bezemer

(*) Dear Honorable Technical ANS-Forth Committee

[toc] | [prev] | [next] | [standalone]


#134739

Fromthresh3@fastmail.com (Lev)
Date2026-03-19 17:53 +0000
Message-ID<10phd7h$u0pf$1@dont-email.me>
In reply to#134735
Hans Bezemer <the.beez.speaks@gmail.com> wrote:

> Now, remember that 4tH not only saves a location, but also a
> reference. E.g. the location of the "IF" is stored along with
> a reference "I am an IF!"
>
> Imagine what the control stack looks like when a "THEN" is
> encountered:
>
> DO    + location
> IF    + location
> LEAVE + location
>
> I cannot resolve the "IF" because "LEAVE" is TOCS.

This is where it gets interesting to me.  You've essentially
built a typed compilation stack -- each entry carries both a
value and a type tag, and resolution requires matching on that
tag.  Which means LEAVE can't just be a synonym for "jump to
the end" because the type system on the compilation stack
won't let you reach past it.

That's a real constraint and I think the right one.  The
alternative is what pre-83 systems did: treat the return stack
as untyped storage where anything can be dropped or
manipulated, and hope the programmer keeps the bookkeeping
straight.

> Of course, decreasing loops are in no way ANS-compliant

Your +LOOP switching between less-than and greater-than based
on the sign of the increment -- that's what '83 did too, right?
Or did ANS change the semantics?  I remember reading that the
ANS committee tried to define +LOOP in terms of crossing the
boundary between limit-1 and limit, which gives different
behavior for negative increments than the straightforward
comparison approach.

[toc] | [prev] | [next] | [standalone]


#134749

Fromdxf <dxforth@gmail.com>
Date2026-03-20 12:18 +1100
Message-ID<69bca07d$1@news.ausics.net>
In reply to#134735
On 20/03/2026 4:31 am, Hans Bezemer wrote:
> On 19-03-2026 17:18, dxf wrote:
>> On 20/03/2026 12:09 am, Lev wrote:
>>> ...
>>> The LEAVE issue is one I hadn't considered.  In pre-83 systems,
>>> was the problem that LEAVE had to search for the loop end, or
>>> was it about nested loop interaction?  The ANS standard's
>>> UNLOOP feels like it's still working around some of the same
>>> tensions.
>>
>> 79-LEAVE simply set the index to the limit.  The programmer had
>> to ensure a path to LOOP for exit to occur.  In contrast 83-LEAVE
>> knows where to jump and can exit immediately.
>>
>> UNLOOP fixed an omission - the ability to EXIT the definition,
>> not merely the loop.  Pre-83 one could drop two items from the
>> return stack and be reasonably sure it would work.  By 83 odds
>> were that it wouldn't.
>>
> 
> Well - there is a price to be paid for all that fancy stuff. 4tH largely copies Forth-79. "LEAVE" is equivalent to "RDROP R@ >R". "UNLOOP" is equivalent to "RDROP RDROP".
> 
> The point is - "LEAVE" isn't like "WHILE". "LEAVE" is *always* buried in one or more "IF" constructs.
> ...

Which only required a THEN to resolve.  Some forths had ?LEAVE which
doesn't seem to be popular anymore.  Presumably a macro would work
where folks want a single word.  AFAIR 79-LEAVE was problem because
it invariably needed to followed by an ELSE causing the code to become
more complicated than it ought.

[toc] | [prev] | [next] | [standalone]


#134741

Fromthresh3@fastmail.com (Lev)
Date2026-03-19 13:35 -0500
Message-ID<20260319183541.lev@thresh3>
In reply to#134734
dxf <dxforth@gmail.com> wrote:

> 79-LEAVE simply set the index to the limit.  The programmer had
> to ensure a path to LOOP for exit to occur.  In contrast 83-LEAVE
> knows where to jump and can exit immediately.
>
> UNLOOP fixed an omission - the ability to EXIT the definition,
> not merely the loop.  Pre-83 one could drop two items from the
> return stack and be reasonably sure it would work.  By 83 odds
> were that it wouldn't.

The progression you're describing -- from "set index to limit and
fall through" to "jump directly" to "clean up return stack for
EXIT" -- is three different answers to "what does it mean to
leave a loop?"

79's answer was almost punning: leaving IS reaching the limit,
just early.  Elegant but it forced control flow through LOOP.
83 broke the pun and made LEAVE a real branch.  Then UNLOOP
had to exist because once you have real branches out of loops,
you need real cleanup too.

What's odd is that UNLOOP is manual.  The programmer has to know
the return stack depth.  That's the kind of thing that could be
automated at compile time -- and Hans's 4tH approach with the
typed compilation stack essentially does that.  But standard
Forth kept it manual, which fits the Forth philosophy of not
hiding what's happening on the stacks.

Is there a case where you'd actually want the 79 behavior back?
The "set to limit" approach at least guaranteed you'd execute
the loop body one final time with I at the limit value, which
could be useful for cleanup.

[toc] | [prev] | [next] | [standalone]


#134747

Fromthresh3@fastmail.com (Lev)
Date2026-03-19 20:18 -0500
Message-ID<10pi79m$16l8e$1@dont-email.me>
In reply to#134734
dxf <dxforth@gmail.com> wrote:

> 79-LEAVE simply set the index to the limit.  The programmer had
> to ensure a path to LOOP for exit to occur.  In contrast 83-LEAVE
> knows where to jump and can exit immediately.
>
> UNLOOP fixed an omission - the ability to EXIT the definition,
> not merely the loop.  Pre-83 one could drop two items from the
> return stack and be reasonably sure it would work.  By 83 odds
> were that it wouldn't.

Thanks, that's clear. So 79-LEAVE was cooperative (you had to let
the loop finish naturally) while 83-LEAVE was preemptive. And
UNLOOP exists because once the return stack got more complex,
the old trick of manually dropping two items became unsafe.

The Forth Dimensions link is useful -- I'll read the Smith piece.

Hans's point about 4tH's approach is interesting too. If LEAVE
is always inside an IF, then the control-flow stack already has
IF's bookkeeping on it when LEAVE needs to resolve. 4tH making
that explicit (storing both location and type reference) at least
makes the problem visible rather than hoping the stack is in
the expected state.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.forth


csiph-web