• Back & Forth - Co-routines

    From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Thu Jan 30 18:42:06 2025
    From Newsgroup: comp.lang.forth

    The lot of you have contributed to this episode - by discussing the
    previous episode on local variables.

    I thank you for your comments - and decided it was worth its own
    episode: https://youtu.be/FH4tWf9vPrA

    More than worth! ;-)

    Hans Bezemer
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Jan 31 18:33:17 2025
    From Newsgroup: comp.lang.forth

    On 31/01/2025 4:42 am, Hans Bezemer wrote:
    The lot of you have contributed to this episode - by discussing the previous episode on local variables.

    I thank you for your comments - and decided it was worth its own episode: https://youtu.be/FH4tWf9vPrA

    More than worth! ;-)

    Thanks Hans!

    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    r> -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Fri Jan 31 08:22:41 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    This kind of implementation leads to the same behaviour as dynamic
    scoping. As long as you don't have quotations or other kinds of
    nested definitions, or if you only access the locals of the innermost definition (as in the quotations in the next standard draft), there is
    no difference from static scoping. But if you have nested definitions
    and access to outer locals, there is a difference, and Knuth's
    man-or-boy test shows the difference. One usually wants static
    scoping, but there are also cases where dynamic scoping is desired.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Jan 31 11:47:34 2025
    From Newsgroup: comp.lang.forth

    In article <49736c0ec0e34ca5d67f4e0d6e8cbe2a080e38ab@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 31/01/2025 4:42 am, Hans Bezemer wrote:
    The lot of you have contributed to this episode - by discussing the previous episode on local variables.

    I thank you for your comments - and decided it was worth its own episode: https://youtu.be/FH4tWf9vPrA

    More than worth! ;-)

    Thanks Hans!

    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?

    I hate TUCK but this code could benefit from RTUCK

    : RTUCK R> >R >R ;
    Obviously this must be low level.

    Groetjes Albert



    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 12:45:11 2025
    From Newsgroup: comp.lang.forth

    Hi,
    Thanks for this video and this implementation of locals.

    But what about the speed of execution?

    I've written this test ( calculte the membership function, fuzzy logic)
    using:
    --stack juggling, the word: tri_mf1
    --global variables, the word: tri_mf2
    --local variables, (gforth), the word: tri_mf3
    --local variables, using this method presented here, the word: tri_mf3

    the program is here after (using gforth):

    : tri_mf1 ( x a b c -- mf) \ stack juggling
    >r >r ( x a ) ( r: c b)
    2dup < if rdrop rdrop 2drop 0 exit then

    ( x a) ( r: c b)
    over ( x a x ) ( r: c b)
    r@ ( x a x b) ( r: c b)
    <
    >r
    2dup >=
    r> and ( x a t) ( r: c b)

    if ( x a) ( r: c b)
    tuck ( a x a)
    - 100 ( a x-a 100) ( r: c b)
    rot ( x-a 100 a ) ( r: c b)
    r> ( x-a 100 a b) ( r: c)
    swap - ( x-a 100 b-a) ( r: c)
    */ rdrop exit
    then

    ( x a ) ( r: c b)
    drop ( x) ( r: c b)
    r@ 2dup ( x b x b) ( r: c b )
    >= ( x b t) ( r: c b)

    rdrop ( x b t ) ( r: c)
    >r ( x b ) ( r: c t)
    over ( x b x ) ( r: c t)
    r> ( x b x t) ( r: c)
    r@ ( x b x t c ) ( r: c)
    swap ( x b x c t) ( r: c)
    >r ( x b x c) ( r: c t)
    < r> and ( x b t) ( r: c)

    if ( x b) ( r: c)
    r@ ( x b c) ( r: c)
    rot - ( b c-x) ( r: c)
    100 ( b c-x 100) ( r: c)
    rot ( c-x 100 b ) ( r: c)
    r> swap - */ exit then
    2drop rdrop
    0
    ;

    variable a
    variable b
    variable c

    : tri_mf2 ( x a b c -- mf) \ global variables
    c ! b ! a !
    dup a @ < if drop 0 exit then
    dup a @ >= over b @ < and if a @ - 100 b @ a @ - */ exit then
    dup b @ >= over c @ < and if c @ swap - 100 c @ b @ - */ exit then
    drop 0

    ;

    : tri_mf3 ( x a b c -- mf) { a b c -- } \ locals à la gforth
    dup a < if drop 0 exit then
    dup a >= over b < and if a - 100 b a - */ exit then
    dup b >= over c < and if c swap - 100 c b - */ exit then
    drop 0
    ;


    : ;: >r ;
    : local r> swap dup >r @ >r ;: r> r> ! ;

    variable a
    variable b
    variable c

    : tri_mf4 ( x a b c -- mf) \ locals new
    a local b local c local
    c ! b ! a !
    dup a @ < if drop 0 exit then
    dup a @ >= over b @ < and if a @ - 100 b @ a @ - */ exit then
    dup b @ >= over c @ < and if c @ swap - 100 c @ b @ - */ exit then
    drop 0
    ;

    for the test I use:
    defer tri_mf

    : test 0 do 20 -50 0 50 tri_mf drop loop ;

    The results:

    ' tri_mf1 is tri_mf ok
    timer-reset 1000000 test .elapsed 94.866300ms ok
    ' tri_mf2 is tri_mf ok
    timer-reset 1000000 test .elapsed 96.399100ms ok
    ' tri_mf3 is tri_mf ok
    timer-reset 1000000 test .elapsed 83.403500ms ok
    ' tri_mf4 is tri_mf ok
    timer-reset 1000000 test .elapsed 211.670300ms ok

    I see that the proposed method is slower than the others

    Any explainations?

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Jan 31 15:55:05 2025
    From Newsgroup: comp.lang.forth

    On 31-01-2025 13:45, ahmed wrote:
    Hi,
    Thanks for this video and this implementation of locals.
    You're welcome.

    But what about the speed of execution?

    Well, that will depend a lot. I mean - you're not very honest if you use
    the built-in primitives of a Forth compiler. If you want to be honest,
    use the reference implementation of Forth 200x. Because primitives
    always win from high level code.

    I measured a size penalty of 4 times and a performance penalty of 10
    times when executing my example DIVIDE word. But then again - 4tH
    doesn't support locals natively. So that is to be expected.

    That is also the reason why I didn't include these findings. It would be dishonest to compare a high level implementation where others offer a implementation using primitives.

    For instance, I'm sure you understand that this benchmark will come out
    quite differently if I run it in 4tH.

    As I said - you can convenience your way out of everything. And no
    matter how fast your Forth, in the end raw assembly will beat
    everything, including C.

    So next time you want to make a point, yes, your native regular
    expression engine *WILL* probably beat even the neatest and most
    cleverly designed high level Forth matching routine.

    I see that the proposed method is slower than the others

    Any explainations?

    Yeah, I understand why you like locals, because your stack juggling
    skills need some polishing. But I got a video on that: https://youtu.be/gfE8arB3uWk

    First the preliminaries:

    : ;then postpone exit postpone then ; immediate
    : >zero dup xor ;
    : spin swap rot ;

    These are 4tH-ese, but I'm attached to them. ;-)
    ( n1 n2 n3 n4 -- n5)
    : calc - >r - 100 r> spin */ ;

    : tri_mf4
    >r rot r> swap >r spin ( c b a R: x )
    dup r@ >= if drop drop >zero rdrop ;then
    over r@ >= over r@ < and if dup r> swap calc ;then drop
    over r@ >= over r@ < and if over r> calc ;then
    rdrop drop >zero
    ;

    If you need more speed, inline CALC.
    BTW, replace "RDROP" with "R> DROP" if you need to.

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 15:16:29 2025
    From Newsgroup: comp.lang.forth

    On Fri, 31 Jan 2025 14:55:05 +0000, Hans Bezemer wrote:

    On 31-01-2025 13:45, ahmed wrote:
    Hi,
    Thanks for this video and this implementation of locals.
    You're welcome.

    But what about the speed of execution?

    Well, that will depend a lot. I mean - you're not very honest if you use
    the built-in primitives of a Forth compiler. If you want to be honest,
    use the reference implementation of Forth 200x. Because primitives
    always win from high level code.

    I measured a size penalty of 4 times and a performance penalty of 10
    times when executing my example DIVIDE word. But then again - 4tH
    doesn't support locals natively. So that is to be expected.

    That is also the reason why I didn't include these findings. It would be dishonest to compare a high level implementation where others offer a implementation using primitives.

    For instance, I'm sure you understand that this benchmark will come out
    quite differently if I run it in 4tH.

    As I said - you can convenience your way out of everything. And no
    matter how fast your Forth, in the end raw assembly will beat
    everything, including C.

    So next time you want to make a point, yes, your native regular
    expression engine *WILL* probably beat even the neatest and most
    cleverly designed high level Forth matching routine.

    I see that the proposed method is slower than the others

    Any explainations?

    Yeah, I understand why you like locals, because your stack juggling
    skills need some polishing. But I got a video on that: https://youtu.be/gfE8arB3uWk

    First the preliminaries:

    : ;then postpone exit postpone then ; immediate
    : >zero dup xor ;
    : spin swap rot ;

    These are 4tH-ese, but I'm attached to them. ;-)
    ( n1 n2 n3 n4 -- n5)
    : calc - >r - 100 r> spin */ ;

    : tri_mf4
    >r rot r> swap >r spin ( c b a R: x )
    dup r@ >= if drop drop >zero rdrop ;then
    over r@ >= over r@ < and if dup r> swap calc ;then drop
    over r@ >= over r@ < and if over r> calc ;then
    rdrop drop >zero
    ;

    If you need more speed, inline CALC.
    BTW, replace "RDROP" with "R> DROP" if you need to.

    Hans Bezemer


    I didn't do this comparison for anything but just to test the
    possibility to integrate it (use it) in my forth programs which need
    speed (fuzzy logic, neural networks).
    I'm not arguing anything about forth or 4th, I'm just a user.

    Thanks

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Jan 31 16:25:58 2025
    From Newsgroup: comp.lang.forth

    On 31-01-2025 08:33, dxf wrote:
    On 31/01/2025 4:42 am, Hans Bezemer wrote:
    The lot of you have contributed to this episode - by discussing the previous episode on local variables.

    I thank you for your comments - and decided it was worth its own episode: https://youtu.be/FH4tWf9vPrA

    More than worth! ;-)

    Thanks Hans!

    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    r> -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?


    I'm sure it works - but IMHO it heavily depends on whether those words
    are primitives or not. E.g. in 4tH this expends to:

    : local r> rot rot dup @ over >r >r ! ;: r> r> ! ;

    And if I want to be pedantic, I have to include two SWAPs as well for
    the proper definition of 2>R and 2R> - not to mention that you
    sometimes *DON'T* want to initialize your locals.

    Another (consequential) disadvantage of this definition is that you have
    to *DEFINE* your words in reverse - a drawback which it shares with the original ANS LOCALS wordset.

    Anyways, it may be useful to some people. Since I tend to use my LOCALs
    in conjunction with the 4tH preprocessor, I stick with the old version.
    It runs this one unmodified:

    : LT1 {: a b | c -- f :}
    CR ." Hello1 " CR a ;
    T{ 3 4 LT1 => 3 }T \ Outputs Hello1

    : LT2 {: a | b c e :}
    CR ." Hello2 " CR ;
    T{ 3 LT2 => }T \ Outputs Hello2

    : LT3 {: a b c -- :}
    CR ." Hello3 " CR ;
    T{ 3 4 5 LT3 => }T \ Outputs Hello3

    : LT4 {: a b c :}
    CR ." Hello4 " CR ;
    T{ 3 4 5 LT4 => }T \ Outputs Hello4

    : LT5 {: a | b c d -- e f g :}
    CR ." Hello5 " CR
    a 2* to b b 2* to c c 2* to d
    b c d ;
    T{ 3 LT5 => 6 12 24 }T \ Outputs Hello5

    But as usual - thanks to the feedback!

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 15:35:40 2025
    From Newsgroup: comp.lang.forth

    On Fri, 31 Jan 2025 14:55:05 +0000, Hans Bezemer wrote:

    On 31-01-2025 13:45, ahmed wrote:
    Hi,
    Thanks for this video and this implementation of locals.
    You're welcome.
    ..
    Any explainations?

    Yeah, I understand why you like locals, because your stack juggling
    skills need some polishing. But I got a video on that: https://youtu.be/gfE8arB3uWk


    I'm still learning and I don't prefer locals or any other method. I just
    use what it comes handy. And yes, I like stack juggling, but I'm not
    very skilled for.

    First the preliminaries:

    : ;then postpone exit postpone then ; immediate
    : >zero dup xor ;
    : spin swap rot ;

    These are 4tH-ese, but I'm attached to them. ;-)
    ( n1 n2 n3 n4 -- n5)
    : calc - >r - 100 r> spin */ ;

    : tri_mf4
    >r rot r> swap >r spin ( c b a R: x )
    dup r@ >= if drop drop >zero rdrop ;then
    over r@ >= over r@ < and if dup r> swap calc ;then drop
    over r@ >= over r@ < and if over r> calc ;then
    rdrop drop >zero
    ;

    This one (tri_mf5) gives better result and thanks for it.
    I find:
    ' tri_mf1 is tri_mf timer-reset 1000000 test .elapsed 88.759600ms ok
    ' tri_mf2 is tri_mf timer-reset 1000000 test .elapsed 100.902500ms ok
    ' tri_mf3 is tri_mf timer-reset 1000000 test .elapsed 86.124300ms ok
    ' tri_mf4 is tri_mf timer-reset 1000000 test .elapsed 209.688300ms ok
    ' tri_mf5 is tri_mf timer-reset 1000000 test .elapsed 96.897100ms ok

    If you need more speed, inline CALC.
    BTW, replace "RDROP" with "R> DROP" if you need to.

    Hans Bezemer


    Thanks for your reply and the way to speedup the method.
    I'll use it, be sure.

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Jan 31 16:43:11 2025
    From Newsgroup: comp.lang.forth

    On 31-01-2025 16:16, ahmed wrote:
    I didn't do this comparison for anything but just to test the
    possibility to integrate it (use it) in my forth programs which need
    speed (fuzzy logic, neural networks).
    I'm not arguing anything about forth or 4th, I'm just a user.

    "But what about the speed of execution?"
    Well, you wanted an explanation - and you got one: primitives will
    always win from fancy, high level implementations. That's why you have
    to test your specific implementation if the documentation isn't clear on
    how certain features are implemented.

    In some environments speed is a minor requirement - the obvious example
    of the difference of a user experience of 0.1s vs. 0.01s (shhh - there
    is none).

    Neither did I argue about 4tH and other Forth implementations - so I
    have no idea where you got that impression. Most Forth implementations
    have different design objectives, reflecting the specific needs of their creators.

    From a user perspective, the story is very simple - pick the one that
    fits you. Who am I to argue with what you need? I don't know you and I
    don't know the task you want to fulfill.

    If I have any beef it's why do you need a 50 line (high level) reference implementation if you can implement the same functionality with one
    single cleverly designed line (which is much more Forth like).

    And yeah - don't use locals at all. Bad habit. Gee - coming from me,
    that's a big surprise.

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 16:14:27 2025
    From Newsgroup: comp.lang.forth

    On Fri, 31 Jan 2025 15:43:11 +0000, Hans Bezemer wrote:

    On 31-01-2025 16:16, ahmed wrote:
    I didn't do this comparison for anything but just to test the
    possibility to integrate it (use it) in my forth programs which need
    speed (fuzzy logic, neural networks).
    I'm not arguing anything about forth or 4th, I'm just a user.

    "But what about the speed of execution?"
    Well, you wanted an explanation - and you got one: primitives will
    always win from fancy, high level implementations. That's why you have
    to test your specific implementation if the documentation isn't clear on
    how certain features are implemented.

    Thanks, for this explanation.

    ..

    From a user perspective, the story is very simple - pick the one that
    fits you. Who am I to argue with what you need? I don't know you and I
    don't know the task you want to fulfill.

    That's what I'm doing.

    If I have any beef it's why do you need a 50 line (high level) reference implementation if you can implement the same functionality with one
    single cleverly designed line (which is much more Forth like).

    Yes, you are right.

    And yeah - don't use locals at all. Bad habit. Gee - coming from me,
    that's a big surprise.

    Hans Bezemer

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 16:30:35 2025
    From Newsgroup: comp.lang.forth

    On Fri, 31 Jan 2025 14:55:05 +0000, Hans Bezemer wrote:
    First the preliminaries:

    : ;then postpone exit postpone then ; immediate
    : >zero dup xor ;
    : spin swap rot ;

    These are 4tH-ese, but I'm attached to them. ;-)
    ( n1 n2 n3 n4 -- n5)
    : calc - >r - 100 r> spin */ ;

    : tri_mf4
    >r rot r> swap >r spin ( c b a R: x )
    dup r@ >= if drop drop >zero rdrop ;then
    over r@ >= over r@ < and if dup r> swap calc ;then drop
    over r@ >= over r@ < and if over r> calc ;then
    rdrop drop >zero
    ;


    I studied this version you've prposed: tri_mf4.
    I find it amazing, comprehensible (redibility) and very clever (compared
    to mine tri_mf1 in the previous post).
    Thanks a lot for it.

    Hans Bezemer

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Jan 31 21:53:45 2025
    From Newsgroup: comp.lang.forth

    On 31-01-2025 17:30, ahmed wrote:
    I studied this version you've prposed: tri_mf4.
    I find it amazing, comprehensible (redibility) and very clever (compared
    to mine tri_mf1 in the previous post).
    Thanks a lot for it.

    Thank you, Ahmed. I honestly appreciate that. It's what I strive to do.

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Fri Jan 31 14:06:00 2025
    From Newsgroup: comp.lang.forth

    melahi_ahmed@yahoo.fr (ahmed) writes:
    : tri_mf3 ( x a b c -- mf) { a b c -- } \ locals à la gforth
    dup a < if drop 0 exit then
    dup a >= over b < and if a - 100 b a - */ exit then
    dup b >= over c < and if c swap - 100 c b - */ exit then
    drop 0
    ;

    This seems more in the locals spirit:

    : blend { a x b -- n } 100 b x - b a - */ ;
    : tri_mf3.1 { x a b c -- mf }
    a x <= x b < AND IF b x a blend EXIT THEN
    b x <= x c < AND IF b x c blend EXIT THEN
    0 ;
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 23:05:15 2025
    From Newsgroup: comp.lang.forth

    On Fri, 31 Jan 2025 22:06:00 +0000, Paul Rubin wrote:

    melahi_ahmed@yahoo.fr (ahmed) writes:
    : tri_mf3 ( x a b c -- mf) { a b c -- } \ locals à la gforth
    dup a < if drop 0 exit then
    dup a >= over b < and if a - 100 b a - */ exit then
    dup b >= over c < and if c swap - 100 c b - */ exit then
    drop 0
    ;

    This seems more in the locals spirit:

    : blend { a x b -- n } 100 b x - b a - */ ;
    : tri_mf3.1 { x a b c -- mf }
    a x <= x b < AND IF b x a blend EXIT THEN
    b x <= x c < AND IF b x c blend EXIT THEN
    0 ;

    Yes, thanks.
    I know that with a little bit of thinking one can get good solutions.

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Fri Jan 31 23:21:19 2025
    From Newsgroup: comp.lang.forth

    Here is another one:

    : blend { b x a -- } 100 x a - b a - */ ;
    : tri_mf3.2 { x a b c -- }
    b x a blend b x c blend min 0 max ;

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Feb 1 11:31:39 2025
    From Newsgroup: comp.lang.forth

    On 1/02/2025 2:25 am, Hans Bezemer wrote:
    ...
    I'm sure it works - but IMHO it heavily depends on whether those words are primitives or not. E.g. in 4tH this expends to:

    : local r> rot rot dup @ over >r >r ! ;: r> r> ! ;

    And if I want to be pedantic, I have to include two SWAPs as well for the proper definition of 2>R and 2R> 

    Of course but for most forths it should be fine.

    - not to mention that you sometimes *DON'T* want to initialize your locals.

    Well, now we're talking about something that's not the norm for locals and
    that may be worth a discussion.


    Another (consequential) disadvantage of this definition is that you have to *DEFINE* your words in reverse - a drawback which it shares with the original ANS LOCALS wordset.

    Drawback for those wanting locals that fake a stack comment. IIRC iForth has LOCAL so clearly not everyone is fussed. If I use locals I'm more likely to use the ANS notation. I notice Forth Inc does too - perhaps why they were so adverse to conceding to { } .



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Feb 1 07:26:11 2025
    From Newsgroup: comp.lang.forth

    Paul Rubin <no.email@nospam.invalid> writes:
    This seems more in the locals spirit:

    : blend { a x b -- n } 100 b x - b a - */ ;
    : tri_mf3.1 { x a b c -- mf }
    a x <= x b < AND IF b x a blend EXIT THEN
    b x <= x c < AND IF b x c blend EXIT THEN
    0 ;

    Forth has a word WITHIN that should come in handy here:

    : tri_mf3.1 { x a b c -- mf }
    x a b within IF b x a blend EXIT THEN
    x b c within IF b x c blend EXIT THEN
    0 ;

    Another alternative, assuming a<=b<=c:

    : tri_mf3.1 { x a b c -- mf }
    case
    x a < ?of 0 endof
    x b < ?of b x a blend endof
    x c < ?of b x c blend endof
    0 0
    endcase ;

    The disadvantage in the latter case is that the above and below cases
    are separate, needing another branch and possibly increasing the
    number of mispredictions. This can be addressed with:

    [undefined] select [if]
    : select ( u1 u2 f -- u )
    if swap then nip ;
    [then]

    : tri_mf3.1 { x a b c -- mf }
    x a c within if
    b x x b < a c select blend
    else
    0
    then ;

    In Gforth (development) SELECT is a primitive which hopefully does not
    branch; in that case you have only one branch here.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Feb 1 07:50:49 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    If I use locals I'm more likely to
    use the ANS notation. I notice Forth Inc does too - perhaps why they were so >adverse to conceding to { } .

    The reason why Forth, Inc. argued against { } is that they support an
    existing code base that uses { } for comments; they use { } comments extensively in SwiftForth, and their customers use it, too. They
    voted for {: :}, so they obviously don't have a problem with the
    ordering of locals in {: :} (which is the same as for { }).

    Using WHERE LOCALS| in SwiftForth x64-Linux 4.0.0-RC89 only brings up
    the definition of LOCALS|, but no uses. "WHERE {:" brings up the
    definition and 5 uses of "{:", all with more than one local; so they
    obviously do not have a problem with the ordering of locals in {: :}.
    Can you elaborate on what you have noticed?

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Sat Feb 1 08:22:01 2025
    From Newsgroup: comp.lang.forth

    On Sat, 1 Feb 2025 7:26:11 +0000, Anton Ertl wrote:

    Paul Rubin <no.email@nospam.invalid> writes:
    This seems more in the locals spirit:

    : blend { a x b -- n } 100 b x - b a - */ ;
    : tri_mf3.1 { x a b c -- mf }
    a x <= x b < AND IF b x a blend EXIT THEN
    b x <= x c < AND IF b x c blend EXIT THEN
    0 ;

    Forth has a word WITHIN that should come in handy here:

    : tri_mf3.1 { x a b c -- mf }
    x a b within IF b x a blend EXIT THEN
    x b c within IF b x c blend EXIT THEN
    0 ;

    Yes, it works fine. Thanks.

    Another alternative, assuming a<=b<=c:

    : tri_mf3.1 { x a b c -- mf }
    case
    x a < ?of 0 endof
    x b < ?of b x a blend endof
    x c < ?of b x c blend endof
    0 0
    endcase ;

    It also works fine without problems.



    The disadvantage in the latter case is that the above and below cases
    are separate, needing another branch and possibly increasing the
    number of mispredictions. This can be addressed with:

    [undefined] select [if]
    : select ( u1 u2 f -- u )
    if swap then nip ;
    [then]

    : tri_mf3.1 { x a b c -- mf }
    x a c within if
    b x x b < a c select blend
    else
    0
    then ;

    This latter gives wrong results:

    -100 -50 0 50 tri_mf3.1 . 0 ok \ this is true
    -50 -50 0 50 tri_mf3.1 . -4900 ok \ false, must be 0
    -10 -50 0 50 tri_mf3.1 . -900 ok \ false, must be 80
    0 -50 0 50 tri_mf3.1 . \ here division by zero
    *the terminal*:47:12: error: Division by zero
    0 -50 0 50 >>>tri_mf3.1<<< .

    I think it must be:
    (the true/false flag must on tos for select as you defined it)

    : tri_mf3.1 { x a b c -- mf }
    x a c within if
    b x a c x b < select blend
    else
    0
    then ;

    and this one works fine.

    -100 -50 0 50 tri_mf3.1 . 0 ok
    -50 -50 0 50 tri_mf3.1 . 0 ok
    -10 -50 0 50 tri_mf3.1 . 80 ok
    0 -50 0 50 tri_mf3.1 . 100 ok
    10 -50 0 50 tri_mf3.1 . 80 ok
    50 -50 0 50 tri_mf3.1 . 0 ok
    100 -50 0 50 tri_mf3.1 . 0 ok


    In Gforth (development) SELECT is a primitive which hopefully does not branch; in that case you have only one branch here.

    - anton


    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Feb 1 21:13:53 2025
    From Newsgroup: comp.lang.forth

    On 1/02/2025 6:50 pm, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    If I use locals I'm more likely to
    use the ANS notation. I notice Forth Inc does too - perhaps why they were so
    adverse to conceding to { } .

    The reason why Forth, Inc. argued against { } is that they support an existing code base that uses { } for comments; they use { } comments extensively in SwiftForth, and their customers use it, too. They
    voted for {: :}, so they obviously don't have a problem with the
    ordering of locals in {: :} (which is the same as for { }).

    IIRC FI was pressed hard for { } but they wouldn't budge. It was odd
    since a single character to delimit a comment was inherently problematic.
    I find it hard to believe FI customers wouldn't have jumped at the chance
    to get a proper comment scheme and nicer looking locals syntax. As it is
    now they're stuck with two lesser things.

    Using WHERE LOCALS| in SwiftForth x64-Linux 4.0.0-RC89 only brings up
    the definition of LOCALS|, but no uses. "WHERE {:" brings up the
    definition and 5 uses of "{:", all with more than one local; so they obviously do not have a problem with the ordering of locals in {: :}.
    Can you elaborate on what you have noticed?

    Interesting since...

    SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022

    85 matches for LOCAL| (a few false positives in that)
    0 matches for {: :} (despite being implemented)

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Feb 1 08:54:41 2025
    From Newsgroup: comp.lang.forth

    melahi_ahmed@yahoo.fr (ahmed) writes:
    On Sat, 1 Feb 2025 7:26:11 +0000, Anton Ertl wrote:
    [undefined] select [if]
    : select ( u1 u2 f -- u )
    if swap then nip ;
    [then]

    : tri_mf3.1 { x a b c -- mf }
    x a c within if
    b x x b < a c select blend
    else
    0
    then ;
    ...
    I think it must be:
    (the true/false flag must on tos for select as you defined it)

    : tri_mf3.1 { x a b c -- mf }
    x a c within if
    b x a c x b < select blend
    else
    0
    then ;

    Yes, thank you. Why did I make this bug? I originally wrote

    x b < if a else c then

    then replaced the IF ELSE THEN with SELECT, but did not change the
    order of arguments accordingly.

    It's an interesting question of whether the ordering of arguments in
    SELECT is optimal. Let's look at the existing uses of SELECT in
    Gforth (only one line given, this comes from WHERE):

    Flag last preferable:
    cell [ 2 cells ] Literal I cell- 2@ <> select \ skip double entries
    0 [: over defers addr>view dup 0= select ;] sections-execute nip ;
    i dup >cfa swap name>string drop cell negate and dup 0= select
    r $substitute over r@ u<= -78 swap select -rot
    dup name>compile >r swap name>interpret state @ select

    Flag first preferable:
    dup 0< 'A' 'B' rot select hold abs #n #esc[
    dup 0< 'D' 'C' rot select hold abs #n #esc[
    dup $80 $20 vt100-modifier @ 2 and select
    cells altkeys ctrlkeys vt100-modifier @ 2 and select
    : .s/d ( -- ) 's' 'd' s? IF ss? ELSE length @ 0= THEN select emit ;
    : .d/s ( -- ) 'd' 's' s? IF ss? ELSE length @ 0= THEN select emit ;

    Does not matter:
    replace-sourceview current-sourceview over select ;
    dup 7 <= IF 'r' 'e' w? select emit ELSE 'r' emit THEN ; "breg2 "breg p? select ELSE "wregs ( " ) THEN THEN
    : .s/p ( -- ) 's' 'p' s? select emit ;
    : .p/s ( -- ) 'p' 's' s? select emit ;
    : .ssereg ( n -- n ) 'y' 'x' l? select emit ." mm" #.r ;

    Unclear:
    0 [: over in-dictionary1? section-start @ and over select ;]

    In the case that someone wants to implement a flag-first SELECT-like
    word, please do not call it SELECT.

    The .S/D and .D/S case is interesting, because it shows a missed
    opportunity for SELECT:

    : .s/d ( -- ) 's' 'd' ss? length @ 0= s? select select emit ;

    This is still preferable flag-first IMO:

    : .s/d ( -- ) s? ss? length @ 0= ffselect 's' 'd' ffselect emit ;

    OTOH, if you consider both .S/D and .D/S, you can factor that further,
    and then flags-last is preferable.

    Anyway, it's water down the river, we won't change it.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Ruvim@ruvim.pinka@gmail.com to comp.lang.forth on Sat Feb 1 15:19:21 2025
    From Newsgroup: comp.lang.forth

    On 2025-01-31 11:33, dxf wrote:

    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    r> -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?



    This approach does not work well with catch/throw. Because `throw` must restore the values of all "local" variables that are used in the
    definitions whose execution is being terminated. And this is difficult
    to implement.


    See also 13.3.3.1, item c, <https://forth-standard.org/standard/locals#subsubsection.13.3.3.1>

    | ABORT shall release all local storage resources,
    | and CATCH / THROW (if implemented) shall release
    | such resources for all definitions whose execution
    | is being terminated.


    --
    Ruvim

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sat Feb 1 13:14:50 2025
    From Newsgroup: comp.lang.forth

    In article <2025Feb1.085049@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    If I use locals I'm more likely to
    use the ANS notation. I notice Forth Inc does too - perhaps why they were so >>adverse to conceding to { } .

    The reason why Forth, Inc. argued against { } is that they support an >existing code base that uses { } for comments; they use { } comments >extensively in SwiftForth, and their customers use it, too. They
    voted for {: :}, so they obviously don't have a problem with the
    ordering of locals in {: :} (which is the same as for { }).

    Not knowing Swiftforth I have introduced { } for anonymous code snippets
    for ciforth. These anonymous snippets work the same in interpret and compile mode,

    { DROP } EXECUTE
    : xxx { DROP } EXECUTE ;

    They must look familiar to those who use "normal" languages ;-) .
    (swiftforth has a point too, { } is used for comment in Pascal.)

    The dispatch table for equality in my lisp (version based on Mark Probst)
    looks like:
    "
    \ For respective: nil pair number builtin symbol special compound
    0
    { = lisp-flag }
    { = lisp-flag }
    { number-num swap number-num = lisp-flag }
    { = lisp-flag }
    { >R symbol-name R> symbol-name $= lisp-flag }
    { = lisp-flag }
    { = lisp-flag }
    (create-table) TO eq?-dispatch
    "

    Now introduce :NONAME and be surprised how clunky this becomes.

    The implementation didn't cost me an arm and a leg:
    "
    ' TASK @ CONSTANT DOCOL
    \ Denotation for lambda, ends with `}
    : { 'SKIP , (FORWARD HERE DOCOL , HERE CELL+ ,
    STATE @ 1 STATE ! ; IMMEDIATE
    : } '(;) , STATE ! >R FORWARD) R> POSTPONE LITERAL
    ; IMMEDIATE
    "

    Considering the elementary character of this, it is written out
    for speed.

    If you have available the 4 brackets of the apocalypse it is
    more straightforward:

    : { (( (s ({) ; IMMEDIATE
    : } >R (}) s) )) R> 'LITERAL EXECUTE ; IMMEDIATE
    [ LITERAL is the only state smart word in ciforth.
    In interpret mode it does nothing.
    In compile mode it compiles a literal. ]

    As a reminder the 4 brackets:
    \ Compact version of :NONAME .. ; not linked in.
    ({) .. (})
    \ Nest dictionary space.
    (( .. ))
    \ (s s) save and restore STATE.
    (s .. s)
    \ Nest definitions (not used in the above)
    ([) .. (])

    In a complex Forth these words may be difficult to implement.


    - anton

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sat Feb 1 13:30:25 2025
    From Newsgroup: comp.lang.forth

    In article <a33bc1882ad45b21b93e051c9be958821dcfb27b@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 1/02/2025 6:50 pm, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    If I use locals I'm more likely to
    use the ANS notation. I notice Forth Inc does too - perhaps why they were so
    adverse to conceding to { } .

    The reason why Forth, Inc. argued against { } is that they support an
    existing code base that uses { } for comments; they use { } comments
    extensively in SwiftForth, and their customers use it, too. They
    voted for {: :}, so they obviously don't have a problem with the
    ordering of locals in {: :} (which is the same as for { }).

    IIRC FI was pressed hard for { } but they wouldn't budge. It was odd
    since a single character to delimit a comment was inherently problematic.

    You got that right. In a language like Forth or assembler, the only good solution is a single character that runs until the end of line, such as
    ; and \ .
    DOC ENDDOC is used to comment pages of code, so that you cannot see it is commented out bleh!

    If your editor isn't capable to turn

    : XXGCD 2DUP SWAP XGCD ( A B D GCD )
    DUP 0< IF NEGATE SWAP NEGATE SWAP THEN
    DUP >R OVER >R ( R: GCD D )
    >R * R> SWAP - / ( A B D GCD -- C )
    R> R> ;

    into

    \ : XXGCD 2DUP SWAP XGCD ( A B D GCD )
    \ DUP 0< IF NEGATE SWAP NEGATE SWAP THEN
    \ DUP >R OVER >R ( R: GCD D )
    \ >R * R> SWAP - / ( A B D GCD -- C )
    \ R> R> ;

    and reverse it, get your money back.

    I find it hard to believe FI customers wouldn't have jumped at the chance
    to get a proper comment scheme and nicer looking locals syntax. As it is
    now they're stuck with two lesser things.

    Not hard to believe.
    Changing millions of lines of code, for a dubious advantage.


    Using WHERE LOCALS| in SwiftForth x64-Linux 4.0.0-RC89 only brings up
    the definition of LOCALS|, but no uses. "WHERE {:" brings up the
    definition and 5 uses of "{:", all with more than one local; so they
    obviously do not have a problem with the ordering of locals in {: :}.
    Can you elaborate on what you have noticed?

    Interesting since...

    SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022

    85 matches for LOCAL| (a few false positives in that)
    0 matches for {: :} (despite being implemented)

    LOCAL| apparently fit the bill. It still is standard. Why change?
    If you have a large code base, uniformity is an advantage.

    Groetjes Albert.
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Sat Feb 1 15:31:01 2025
    From Newsgroup: comp.lang.forth

    On Fri, 31 Jan 2025 12:45:11 +0000, ahmed wrote:

    Hi,
    Thanks for this video and this implementation of locals.

    But what about the speed of execution?
    [..]
    The results:

    ' tri_mf1 is tri_mf ok
    timer-reset 1000000 test .elapsed 94.866300ms ok
    ' tri_mf2 is tri_mf ok
    timer-reset 1000000 test .elapsed 96.399100ms ok
    ' tri_mf3 is tri_mf ok
    timer-reset 1000000 test .elapsed 83.403500ms ok
    ' tri_mf4 is tri_mf ok
    timer-reset 1000000 test .elapsed 211.670300ms ok

    I see that the proposed method is slower than the others

    Any explainations?

    I had to modify ;: and LOCALE aka LOCAL for iForth
    ( tail-call optimization is forced off with `[ -OPT ]` ).

    The loops here are 1000 x larger (timing goes from ms to seconds)
    so that they can be properly compared with your results. However,
    the outcome is qualitatively the same: tri-mf4 is 3x worse than
    the others. PARAM| is fastest, but it can only shine when
    there are less than 3 stack parameters.

    : ;: >r [ -OPT ] ;
    : locale r> swap dup >r @ >r ;: r> r> ! [ -OPT ] ;

    : tri_mf4 ( x a b c -- mf) \ locals new
    c locale b locale a locale
    c ! b ! a !
    dup a @ < if drop 0 exit then
    dup a @ >= over b @ < and if a @ - 100 b @ a @ - */ exit then
    dup b @ >= over c @ < and if c @ swap - 100 c @ b @ - */ exit then
    drop 0
    ;

    defer tri_mf

    : test 0 do 20 -50 0 50 tri_mf drop loop ;

    : DO-TEST
    CR ." \ The results:"
    CR ." \ tri_mf1: " ['] tri_mf1 [is] tri_mf
    timer-reset #1000000000 test .elapsed ." ( 94.866 s)"
    CR ." \ tri_mf2: " ['] tri_mf2 [is] tri_mf
    timer-reset #1000000000 test .elapsed ." ( 96.399 s)"
    CR ." \ tri_mf3: " ['] tri_mf3 [is] tri_mf
    timer-reset #1000000000 test .elapsed ." ( 83.403 s)"
    CR ." \ tri_mf4: " ['] tri_mf4 [is] tri_mf
    timer-reset #1000000000 test .elapsed ." ( 211.670 s)" ;

    FORTH> DO-TEST
    \ The results:
    \ tri_mf1: 3.273 seconds elapsed. ( 94.866 s)
    \ tri_mf2: 2.727 seconds elapsed. ( 96.399 s)
    \ tri_mf3: 2.910 seconds elapsed. ( 83.403 s)
    \ tri_mf4: 8.006 seconds elapsed. ( 211.670 s) ok

    The explanation: execution speed is by no means the main goal
    of Forth. Who cares about a factor of 30 or 40?

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Feb 1 17:30:24 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    Interesting since...

    SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022

    85 matches for LOCAL| (a few false positives in that)
    0 matches for {: :} (despite being implemented)

    Apparently your search for {: is broken. Here's what I get:

    [/usr/local/src/SwiftForth-3.11.0:155305] rg -i -c 'locals[|]' unsupported/fslib/library/integral.f:4
    unsupported/fslib/library/polrat.f:4
    unsupported/fslib/library/svd.f:9
    unsupported/fslib/library/gaussj.f:13
    unsupported/fslib/library/amoeba.f:2
    unsupported/fslib/library/levmarq.f:7
    lib/options/rstruct.f:4
    lib/options/win32/sprintf.f:1
    lib/options/win32/screensaver.f:1
    lib/options/win32/gditools.f:6
    lib/options/win32/gdiext.f:2
    lib/options/win32/turtle.f:1
    unsupported/contrib/formattext.f:2
    lib/options/win32/boxed.f:9
    lib/samples/win32/rndlines.f:1
    lib/samples/win32/scribble.f:1
    lib/samples/win32/tetris/guitetris.f:1
    lib/samples/win32/showfonts.f:1
    lib/samples/win32/mdi.f:1
    src/ide/exception.f:1
    src/ide/strings.f:2
    src/ide/localvariables.f:4
    src/ide/win32/editor.f:1
    src/ide/win32/winmgmt.f:3
    src/ide/win32/tty/repaint.f:1
    src/ide/win32/tty/tty.f:1
    lib/samples/macos/mac/cocoa/cocoastarter.f:1 lib/samples/macos/mac/doc/CHANGES.txt:1

    [/usr/local/src/SwiftForth-3.11.0:155306] rg -i -c '[{]:'
    src/ide/aswoop.f:3
    src/ide/localvariables.f:4

    [/usr/local/src/SwiftForth-3.11.0:155307] + /usr/local/src/SwiftForth-4.0.0-RC89 /usr/local/src/SwiftForth-3.11.0 /usr/local/src/SwiftForth-3.11.0

    [/usr/local/src/SwiftForth-4.0.0-RC89:155308] rg -i -c 'locals[|]' src/ide/locals.f:5
    src/arch/i386/ide/exception.f:1
    src/arch/x64/ide/exception.f:1
    unsupported/contrib/formattext.f:2 unsupported/forth-2012-tests/localstest.fth:1 unsupported/fslib/library/integral.f:4
    unsupported/fslib/library/polrat.f:4
    unsupported/fslib/library/svd.f:9
    unsupported/fslib/library/gaussj.f:13
    unsupported/fslib/library/levmarq.f:7
    unsupported/fslib/library/amoeba.f:2

    [/usr/local/src/SwiftForth-4.0.0-RC89:155309] rg -i -c '[{]:' unsupported/forth-2012-tests/localstest.fth:38
    src/ide/aswoop.f:3
    src/ide/strings.f:2
    src/ide/locals.f:4
    src/ide/imports.f:2
    src/arch/x64/decode.f:1

    Apparently the use of LOCALS| is connected mostly with win32 files,
    which do not come with 4.0.0-RC89 in the version I use. And most of
    the remaining uses of LOCALS| are in unsupported libraries, in
    particular the Forth Scientific Library. The tool I used for this is
    ripgrep, if anybody is wondering.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Feb 2 11:16:45 2025
    From Newsgroup: comp.lang.forth

    On 2/02/2025 4:30 am, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    Interesting since...

    SwiftForth i386-Win32 3.11.9-RC1 01-Sep-2022

    85 matches for LOCAL| (a few false positives in that)
    0 matches for {: :} (despite being implemented)

    Apparently your search for {: is broken. Here's what I get:
    ...

    Apparently the use of LOCALS| is connected mostly with win32 files,
    which do not come with 4.0.0-RC89 in the version I use. And most of
    the remaining uses of LOCALS| are in unsupported libraries, in
    particular the Forth Scientific Library. The tool I used for this is ripgrep, if anybody is wondering.

    I didn't think to exclude fslib which reduces the LOCAL| count considerably. Still I get no bona fide uses for {: :} at least in the distribution I have.



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Feb 2 11:22:29 2025
    From Newsgroup: comp.lang.forth

    On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
    ...

    { } is used for comment in Pascal.

    That's interesting. When did that come in, and why, given the issues?

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Feb 2 16:03:25 2025
    From Newsgroup: comp.lang.forth

    On 1/02/2025 10:19 pm, Ruvim wrote:
    On 2025-01-31 11:33, dxf wrote:

    Not sure if previously mentioned but here's another version of LOCAL

    : ;:  >r ;

    : LOCAL ( x adr -- )
       r> -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A  variable B  8 a !  7 b !

    : divide ( a b -- )  b local  a local
       a @  b @  /  . cr  ;

    15 3 divide  a ? b ?



    This approach does not work well with catch/throw. Because `throw` must restore the values of all "local" variables that are used in the definitions whose execution is being terminated. And this is difficult to implement.
    ...

    It is locals on the cheap. When I've resorted to something like this it's because I needed re-entrancy on a variable and full-blown locals weren't worth loading. As I never considered catch/throw until you mentioned it, presumably it wasn't an issue in those cases. But yes, it warrants a warning.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Feb 2 07:39:26 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
    { } is used for comment in Pascal.

    That's interesting. When did that come in, and why, given the issues?

    Good question. My memory is only of (* *), but indeed Section 6.1.8
    of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
    and { can be used interchangeably, as well as *) and }.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Feb 2 21:08:19 2025
    From Newsgroup: comp.lang.forth

    On 2/02/2025 6:39 pm, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
    { } is used for comment in Pascal.

    That's interesting. When did that come in, and why, given the issues?

    Good question. My memory is only of (* *), but indeed Section 6.1.8
    of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
    and { can be used interchangeably, as well as *) and }.

    Looking at a several online manuals and tutorials the rules re mixing, single/multiple lines, nesting etc they all seem to vary.

    When a comments proposal (Jonah Thomas?) was made on c.l.f it quickly
    ran into the weeds too :)

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Feb 2 12:05:04 2025
    From Newsgroup: comp.lang.forth

    In article <2025Feb2.083926@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
    { } is used for comment in Pascal.

    That's interesting. When did that come in, and why, given the issues?

    Good question. My memory is only of (* *), but indeed Section 6.1.8
    of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
    and { can be used interchangeably, as well as *) and }.

    The first publication of Pascal was IIRC

    1975
    Pascal , user manual and report.
    Jensen/Wirth
    ISBN 0-387-90144-2

    Uses { } in all examples, and it is referenced in chapter 1, briefly.
    At the time not all keyboard had curly brackets. The alternative
    (* and *) is mentionned in chapter 1 too.


    - anton

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Feb 2 12:13:54 2025
    From Newsgroup: comp.lang.forth

    In article <vnkvvq$2a5o$1@dont-email.me>, Ruvim <ruvim.pinka@gmail.com> wrote: >On 2025-01-31 11:33, dxf wrote:

    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    r> -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?



    This approach does not work well with catch/throw. Because `throw` must >restore the values of all "local" variables that are used in the
    definitions whose execution is being terminated. And this is difficult
    to implement.


    See also 13.3.3.1, item c, ><https://forth-standard.org/standard/locals#subsubsection.13.3.3.1>

    | ABORT shall release all local storage resources,
    | and CATCH / THROW (if implemented) shall release
    | such resources for all definitions whose execution
    | is being terminated.

    Nice catch!

    However, this is highly artificial. You have to have a recursive routine in this
    vein:

    RECURSIVE
    : fun .. fun ... fun . 'fun CATCH .. fun ... ;

    otherwise the global VARIABLE's can be ignored.

    I would be interested to see a remotely plausible example of this.
    Mixing recursion and exception is ill advised by iq<160.

    Groetjes Albert




    --
    Ruvim

    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Feb 2 14:32:27 2025
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl writes:
    The first publication of Pascal was IIRC

    1975
    Pascal , user manual and report.
    Jensen/Wirth
    ISBN 0-387-90144-2

    Uses { } in all examples, and it is referenced in chapter 1, briefly.

    "Programming in Modula-2" Second Edition contains the "Report on The Programming Language Modula-2", and only (* and *) are defined there
    as delimiting comments. It says that comments are nestable.

    I also have a book on Pascal: "Pascal Handbuch" by E. Floegel. In
    Figure 3.31 on page 15 it shows (* and *), but not { and } as
    "Verwendete Zeichen in Pascal" (used characters in Pascal, although
    the intention is probably to show the symbolic lexemes).

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bernd Linsel@bl1-thispartdoesnotbelonghere@gmx.com to comp.lang.forth on Sun Feb 2 16:57:21 2025
    From Newsgroup: comp.lang.forth

    On 02.02.25 15:32, Anton Ertl wrote:
    albert@spenarnc.xs4all.nl writes:
    The first publication of Pascal was IIRC

    1975
    Pascal , user manual and report.
    Jensen/Wirth
    ISBN 0-387-90144-2

    Uses { } in all examples, and it is referenced in chapter 1, briefly.


    I also have a book on Pascal: "Pascal Handbuch" by E. Floegel. In
    Figure 3.31 on page 15 it shows (* and *), but not { and } as
    "Verwendete Zeichen in Pascal" (used characters in Pascal, although
    the intention is probably to show the symbolic lexemes).


    Before IBM PC compatibles with their CP 437 became ubiquituous, the
    characters [ \ ] { | } ~ were commonly replaced with language-specific
    glyphs, in German e.g. with the umlauts and sz-ligature.

    This is the reason that in German publications Pascal sources often used
    (* ... *) for comments, and (. ... .) for indices (instead of [...]),
    because otherwise comments would have appeared as ä ... ü, and indices
    as Ä ... Ü.
    --
    Bernd Linsel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sun Feb 2 13:26:22 2025
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl writes:
    I would be interested to see a remotely plausible example of this.
    Mixing recursion and exception is ill advised by iq<160.

    The recursive function calls something that throws an exception, and it
    should be ok to think about those things separately.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Feb 3 14:46:56 2025
    From Newsgroup: comp.lang.forth

    On 3/02/2025 8:26 am, Paul Rubin wrote:
    albert@spenarnc.xs4all.nl writes:
    I would be interested to see a remotely plausible example of this.
    Mixing recursion and exception is ill advised by iq<160.

    The recursive function calls something that throws an exception, and it should be ok to think about those things separately.

    Depends on where the CATCH is located.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Ruvim@ruvim.pinka@gmail.com to comp.lang.forth on Mon Feb 3 13:07:36 2025
    From Newsgroup: comp.lang.forth

    On 2025-02-02 15:13, albert@spenarnc.xs4all.nl wrote:
    In article <vnkvvq$2a5o$1@dont-email.me>, Ruvim <ruvim.pinka@gmail.com> wrote:
    On 2025-01-31 11:33, dxf wrote:

    Not sure if previously mentioned but here's another version of LOCAL

    : ;: >r ;

    : LOCAL ( x adr -- )
    r> -rot dup @ over 2>r ! ;: 2r> ! ;

    variable A variable B 8 a ! 7 b !

    : divide ( a b -- ) b local a local
    a @ b @ / . cr ;

    15 3 divide a ? b ?



    This approach does not work well with catch/throw. Because `throw` must
    restore the values of all "local" variables that are used in the
    definitions whose execution is being terminated. And this is difficult
    to implement.


    See also 13.3.3.1, item c,
    <https://forth-standard.org/standard/locals#subsubsection.13.3.3.1>

    | ABORT shall release all local storage resources,
    | and CATCH / THROW (if implemented) shall release
    | such resources for all definitions whose execution
    | is being terminated.

    Nice catch!

    However, this is highly artificial. You have to have a recursive routine in this
    vein:

    RECURSIVE
    : fun .. fun ... fun . 'fun CATCH .. fun ... ;

    otherwise the global VARIABLE's can be ignored.

    I would be interested to see a remotely plausible example of this.
    Mixing recursion and exception is ill advised by iq<160.


    Recursion is not necessary. It is enough to use the same-name "local" variables in different functions, some of which throw exceptions, and
    other catch exceptions.

    An artificial example:


    : local ( x2 addr1 -- ; R: nest-sys1 -- x1 addr1 nest-sys.xt nest-sys1 )
    \ This definition assumes that nest-sys size is 1 cell,
    \ and xt is a subtype of nest-sys
    r> ( x2 addr nest-sys1 )
    over dup @ >r >r [: 2r> ! ;] >r
    ( x2 addr1 nest-sys1 ) >r !
    ;


    : idiv ( n1 n2\0 -- n3 | n1 0 -- never )
    dup if / exit then -10 throw
    ;

    variable a
    variable b

    : foo ( n1 n2 -- )
    b local a local
    a @ b @ idiv
    ." idiv result is " . cr
    ;
    : bar ( u1 -- u1 )
    a local
    100 a @ ['] foo catch if 2drop then
    a @
    ;

    0 bar .
    \ this must print 0, but will print 10



    --
    Ruvim
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Feb 3 13:19:15 2025
    From Newsgroup: comp.lang.forth

    In article <vnq10p$162l3$1@dont-email.me>,
    Ruvim <ruvim.pinka@gmail.com> wrote:
    On 2025-02-02 15:13, albert@spenarnc.xs4all.nl wrote:


    Recursion is not necessary. It is enough to use the same-name "local" >variables in different functions, some of which throw exceptions, and
    other catch exceptions.

    An artificial example:


    : local ( x2 addr1 -- ; R: nest-sys1 -- x1 addr1 nest-sys.xt nest-sys1 )
    \ This definition assumes that nest-sys size is 1 cell,
    \ and xt is a subtype of nest-sys
    r> ( x2 addr nest-sys1 )
    over dup @ >r >r [: 2r> ! ;] >r
    ( x2 addr1 nest-sys1 ) >r !
    ;


    : idiv ( n1 n2\0 -- n3 | n1 0 -- never )
    dup if / exit then -10 throw
    ;

    variable a
    variable b

    : foo ( n1 n2 -- )
    b local a local
    a @ b @ idiv
    ." idiv result is " . cr
    ;
    : bar ( u1 -- u1 )
    a local
    100 a @ ['] foo catch if 2drop then
    a @
    ;

    0 bar .
    \ this must print 0, but will print 10


    You share the same global storage for local's in different
    words.
    Try this with naming the local in bar `` c ''.

    I maintain that if you are not in a recursive call for
    a function with locals, and you try to catch the same function
    call, everything is fine.
    The challenge I posed remains, find a realistic scenarion that
    leads to problems.

    Groetjes Albrt

    --
    Ruvim
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Mon Feb 3 12:57:50 2025
    From Newsgroup: comp.lang.forth

    albert@spenarnc.xs4all.nl writes:
    I maintain that if you are not in a recursive call for
    a function with locals, and you try to catch the same function
    call, everything is fine.

    The thing about exceptions is that they occur unexpectedly. Example:
    your recursive function prints something, and that works the first few
    times, but then the printer runs out of paper and there is an i/o
    exception. It's not the recursive function's job to handle this. The exception throws to some outer level handler that asks the user to fix
    the problem.

    Adding (LOCAL) to a Forth interpreter should normally not be too
    difficulot, if you control the interpreter implementation. It's the
    right way to do stuff like this. Why mess around with all that awful
    stack juggling for a half-working and woefully slow solution?
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Tue Feb 4 13:26:26 2025
    From Newsgroup: comp.lang.forth

    In article <874j1aycdt.fsf@nightsong.com>,
    Paul Rubin <no.email@nospam.invalid> wrote:
    albert@spenarnc.xs4all.nl writes:
    I maintain that if you are not in a recursive call for
    a function with locals, and you try to catch the same function
    call, everything is fine.

    The thing about exceptions is that they occur unexpectedly.
    Yeah right.

    Think about it precisely.
    You are in fun , recursively called from fun. A throw occurs in
    this invocation but not from the external invocation.
    You did not catch it in the external fun (otherwise all would be under control). Can that cause problems by no restoring the variable?

    your recursive function prints something, and that works the first few
    times, but then the printer runs out of paper and there is an i/o
    exception. It's not the recursive function's job to handle this. The >exception throws to some outer level handler that asks the user to fix
    the problem.

    The printer runs out of paper during a recursive fibonacci call where you
    print physically all the iteration stuff on a separate page.
    You add new paper to the printer and you want to continue.
    That is not a good example.
    You call 100 'fib catch (don't mind the paper spill, but yes
    the printer is guaranteed to run out of paper).
    The problem is that you cannot recover! The catch makes no sense,
    because the throw is made from in inner fib call.
    Or do you can propose to adorn all recursive calls
    : fib ...
    'fib catch ( enormous recovery for all cases including printer errors )
    ...
    'fib catch ( enormous recovery for all cases including printer errors )
    ..
    ;


    Adding (LOCAL) to a Forth interpreter should normally not be too
    difficulot, if you control the interpreter implementation. It's the
    right way to do stuff like this. Why mess around with all that awful
    stack juggling for a half-working and woefully slow solution?

    That is not the point. We are discussing whether or not the
    present solution is possible.
    It is an academic discussion, because I don't use locals at all,
    if they are absolutely necessary I use my enhanced `[ instead
    of any style of locals

    : root [ variable a variable b variable c ]
    c ! b ! a !
    \ now insert the famous quadratic root formula
    [ hide a hide b hide c ] \ Prevent "not unique messages"
    ;

    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)
    It is perfectly clear that this doesn't work where root
    call itself recursively. But it doesn't call itself, so fine.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From antispam@antispam@fricas.org (Waldek Hebisch) to comp.lang.forth on Thu Feb 6 01:38:57 2025
    From Newsgroup: comp.lang.forth

    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
    { } is used for comment in Pascal.

    That's interesting. When did that come in, and why, given the issues?

    Good question. My memory is only of (* *), but indeed Section 6.1.8
    of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
    and { can be used interchangeably, as well as *) and }.

    '{' and '}' are original Pascal comments. I do not think they have
    any issue beyond normal ones, that is inability to put '}' as
    part of a comment. Since comments were intended to be text and
    '}' is not used as normal part of text presumably inability to
    put '}' inside a comment was deemed as non-issue.

    Pascal was bases on ASCII, but IBM mainframes used EBCDIC which
    missed several useful ASCII characters, notably '{', '}',
    '[', '[', so Pascal implementations on IBM mainframes used
    alternate sequences. The alternative seqences were standarized
    together with originals.

    More generally, Wirth had rather rigid view how "good" program
    should look like and this view was enforced by Pascal compilers.
    Practical Pascals and later Extended Pascal were much more
    flexible.
    --
    Waldek Hebisch
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Thu Feb 6 14:33:23 2025
    From Newsgroup: comp.lang.forth

    On 6/02/2025 12:38 pm, Waldek Hebisch wrote:
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    On 1/02/2025 11:14 pm, albert@spenarnc.xs4all.nl wrote:
    { } is used for comment in Pascal.

    That's interesting. When did that come in, and why, given the issues?

    Good question. My memory is only of (* *), but indeed Section 6.1.8
    of https://www.standardpascal.org/iso7185.pdf makes it clear that (*
    and { can be used interchangeably, as well as *) and }.

    '{' and '}' are original Pascal comments. I do not think they have
    any issue beyond normal ones, that is inability to put '}' as
    part of a comment. Since comments were intended to be text and
    '}' is not used as normal part of text presumably inability to
    put '}' inside a comment was deemed as non-issue.

    Pascal was bases on ASCII, but IBM mainframes used EBCDIC which
    missed several useful ASCII characters, notably '{', '}',
    '[', '[', so Pascal implementations on IBM mainframes used
    alternate sequences. The alternative seqences were standarized
    together with originals.

    More generally, Wirth had rather rigid view how "good" program
    should look like and this view was enforced by Pascal compilers.
    Practical Pascals and later Extended Pascal were much more
    flexible.

    From Wirth's own examples it appears { } was used much like forth uses
    ( ) or \ i.e. as an inline code comment. Getting back to FI, its choice
    of { } as a general block comment seems particularly ill-considered given
    ( ) \ already existed. Unlike Pascal { } was never intended as an inline
    code comment.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From hohl@hohl@isartext.de (HenryHH) to comp.lang.forth on Thu Feb 6 06:47:59 2025
    From Newsgroup: comp.lang.forth

    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:

    ... if they are absolutely necessary I use my enhanced `[ instead
    of any style of locals

    : root [ variable a variable b variable c ]
    c ! b ! a !
    \ now insert the famous quadratic root formula
    [ hide a hide b hide c ] \ Prevent "not unique messages"
    ;

    Hello Albert,

    why is an enhanced [ necessary for this?
    Couldn't you simply write:

    variable a variable b variable c

    : root ( a b c -- root)
    c ! b ! a !
    \ now insert the famous quadratic root formula
    ;

    hide a hide b hide c \ Prevent "not unique messages"

    Henry
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Feb 6 09:20:16 2025
    From Newsgroup: comp.lang.forth

    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)

    Given that a Forth system supports quotations and xt-locals,
    nested definitions are easy to implement. BTW xt-locals exist
    f.ex. in gforth. They hold xt's and when called execute the xt
    instead of pushing it to the stack as normal locals would do.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Feb 6 12:05:07 2025
    From Newsgroup: comp.lang.forth

    In article <73a87ff17586b02ae110516bfb76956e@www.novabbs.com>,
    HenryHH <hohl@isartext.de> wrote:
    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:

    ... if they are absolutely necessary I use my enhanced `[ instead
    of any style of locals

    : root [ variable a variable b variable c ]
    c ! b ! a !
    \ now insert the famous quadratic root formula
    [ hide a hide b hide c ] \ Prevent "not unique messages"
    ;

    Hello Albert,

    why is an enhanced [ necessary for this?
    Couldn't you simply write:

    variable a variable b variable c

    : root ( a b c -- root)
    c ! b ! a !
    \ now insert the famous quadratic root formula
    ;

    hide a hide b hide c \ Prevent "not unique messages"

    You could, but now it doesn't look like a local variable,
    isn't it?
    You remark serves to show that local values (why do they call
    them local variables) are largely superfluous.

    P.S.
    Maybe
    [ variable a variable b variable c
    : D b @ DUP * a @ b @ 4 * - ; ]
    ..
    [ hide a .... hide D ]
    ..
    is more convincing?


    Henry

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Thu Feb 6 12:11:28 2025
    From Newsgroup: comp.lang.forth

    In article <3c3bdb056696f15c43fa512b5366002d@www.novabbs.com>,
    minforth <minforth@gmx.net> wrote:
    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)

    Given that a Forth system supports quotations and xt-locals,
    nested definitions are easy to implement. BTW xt-locals exist
    f.ex. in gforth. They hold xt's and when called execute the xt
    instead of pushing it to the stack as normal locals would do.

    Right. I've shown that it is easy, that is nothing new.
    What also isn't new that gforth insists on introducing another
    special syntax, words and idioms that are unnecessary.
    With my enhanced [ ] pair, you can introduce whatever local
    widgets, in particular objects, you choose.

    The goal of language design is not to overload with features,
    but attain expressiveness with the least amount of concepts.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Feb 6 12:36:39 2025
    From Newsgroup: comp.lang.forth

    On Thu, 6 Feb 2025 11:11:28 +0000, albert@spenarnc.xs4all.nl wrote:

    With my enhanced [ ] pair, you can introduce whatever local
    widgets, in particular objects, you choose.

    The goal of language design is not to overload with features

    But haven't you overloaded the old [ ] with new features now? ;-)
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Feb 6 12:57:12 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)

    Given that a Forth system supports quotations and xt-locals,
    nested definitions are easy to implement.

    You mean:

    : foo [: ." xyz" ;] {: xt: bar :} bar ;

    Sure, you then get a local that behaves similar to a nested
    definition, but I don't think anyone would want to do that.

    And it uses proper locals as part of the mechanism, whereas many
    contributions in the thread seem to have the goal of doing something
    that may require less implementation effort, but also does not do
    everything proper locals do (e.g., work with exceptions), and then try
    to Jedi away the cases that do not work.

    BTW xt-locals exist
    f.ex. in gforth. They hold xt's and when called execute the xt
    instead of pushing it to the stack as normal locals would do.

    We call them defer-flavoured, and the more usual locals
    value-flavoured. In the example above the "xt:" means that the next
    name is that of a defer-flavoured local.

    When Bernd Paysan introduced defer-flavoured locals, I was sceptical, especially given the experience with variable-flavoured locals which
    have been in Gforth since 1994 and are barely used. But it turns out
    that when a local contains an xt, using a defer-flavoured local is
    often more appropriate than a value-flavoured local. This is: you can
    use either (use l EXECUTE when l is value-flavoured and you want to
    execute it, or use ACTION-OF l when l is defer-flavoured and you want
    its value), but in many cases you want to execute an xt you pass,
    sometimes multiple times.

    An example is the generation of code for 2-stage division by
    constants:

    : lit/, {: divisor xt: stage1 xt: stage2 -- :}
    next-section staged/-size small-allot previous-section {: addr :}
    divisor addr stage1 ]] addr stage2 [[ ;

    The first line allocates memory for storing the inverse of the divisor
    in ADDR. The second line first converts from the divisor to the
    inverse in stage 1 of the division when the division is compiled, and
    compiles code for performing stage 2 of the division (multiplying the
    dividend (available only at run-time) with the inverse). It also
    demonstrates that when using a defer-flavoured local inside ]]...[[,
    the xt in the local is COMPILE,d, not EXECUTEd.

    With value-flavoured locals that would have been:

    : lit/, {: divisor stage1 stage2 -- :}
    next-section staged/-size small-allot previous-section {: addr :}
    divisor addr stage1 execute ]] addr [[ stage2 compile, ;

    While the mechanism is more obvious here, the intent is more obvious
    in the version with defer-flavoured locals (at least if you understand
    the code). And of course the orthodox traditional Forther would have
    written this without locals at all:

    : lit/, ( divisor stage1 stage2 -- )
    >r >r >r next-section staged/-size small-allot previous-section ( addr )
    r> dup r> execute ( addr )
    postpone literal r> compile, ;

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Feb 6 13:59:21 2025
    From Newsgroup: comp.lang.forth

    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:

    minforth@gmx.net (minforth) writes:
    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)

    Given that a Forth system supports quotations and xt-locals,
    nested definitions are easy to implement.

    You mean:

    : foo [: ." xyz" ;] {: xt: bar :} bar ;

    Sure, you then get a local that behaves similar to a nested
    definition, but I don't think anyone would want to do that.

    Yes, that's the mechanism. Actually I use it with some syntactic
    sugar for better readability:

    : foo
    <: bar ." xyz" ;>
    bar
    ;

    I find this quite handy, since upvalues (locals within foo's
    context) are accessible from within bar.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Feb 7 01:59:53 2025
    From Newsgroup: comp.lang.forth

    On 7/02/2025 12:59 am, minforth wrote:
    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:

    minforth@gmx.net (minforth) writes:
    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)

    Given that a Forth system supports quotations and xt-locals,
    nested definitions are easy to implement.

    You mean:

    : foo [: ." xyz" ;] {: xt: bar :} bar ;

    Sure, you then get a local that behaves similar to a nested
    definition, but I don't think anyone would want to do that.

    Yes, that's the mechanism. Actually I use it with some syntactic
    sugar for better readability:

    : foo
       <: bar ." xyz" ;>
     bar
    ;

    I find this quite handy, since upvalues (locals within foo's
    context) are accessible from within bar.

    AFAIR 200x nested definitions were justified on the grounds named
    definitions were neither needed nor wanted and access to external
    locals not necessary. Somebody miscalculated?

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Feb 6 15:46:23 2025
    From Newsgroup: comp.lang.forth

    There is indeed a restriction in standard §3.4:

    "A program shall not attempt to nest compilation of definitions.
    During the compilation of the current definition, a program
    shall not execute any defining word, :NONAME, or any definition
    that allocates dictionary data space."

    However because local names are not compiled into dictionary data
    space, but use their own transient dictionary entries, which
    disappear after compilation, this restriction as of $3.4 does not
    apply to embedded functions emulated by xt-locals, aka
    defer-flavoured locals.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Feb 6 17:06:59 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    : foo
    <: bar ." xyz" ;>
    bar
    ;

    I find this quite handy, since upvalues (locals within foo's
    context) are accessible from within bar.

    Do you implement proper static scoping? I.e., does your system pass
    the man-or-boy test. What about returning xts that reference outer
    locals, e.g.:

    : n+ ( n -- xt ) {: n :} [: n + ;] ;
    5 n+ constant 5+
    3 5+ execute .
    7 5+ execute .

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Feb 6 17:46:40 2025
    From Newsgroup: comp.lang.forth

    I don't think so. This is what happens now:

    MinForth 3.6 (32 bit)
    # : n+ ( n -- xt ) {: n :} [: n + ;] ; ok
    # 5 n+ constant 5+ ok
    # 3 5+ execute . 8 ok
    # 7 5+ execute . 12 ok
    #

    I toyed with the idea of "passing" the man-or-boy test
    but did not pursue it last year due to health problems. :-(

    At least writing to upvalues works:

    # : m+ {: m :} <: inc 1 +to m ;> inc inc m . ; ok
    # 2 m+ 4 ok
    #
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Thu Feb 6 17:20:51 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    On 7/02/2025 12:59 am, minforth wrote:
    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:
    AFAIR 200x nested definitions were justified on the grounds named
    definitions were neither needed nor wanted

    Really? There's a proposal to eliminate named definitions? That's
    news to me.

    There are cases where you need to pass an xt to some word, and where
    the xt does not merit a name, e.g.,

    : (where) ( "name" -- ) \ gforth-internal
    (') [: over = ;] forwheres
    drop -1 where-index ! ;

    Of course, one could do that without quotations:

    : (where-helper) over = ;

    : (where) ( "name" -- ) \ gforth-internal
    (') ['] (where-helper) forwheres
    drop -1 where-index ! ;

    But it's more convenient and readable with quotations.

    and access to external
    locals not necessary.

    It's more that anything proper is pretty hard to implement and there
    was not enough demand for that nor existing practice that anybody
    wanted to propose for standardization.

    However, the topic came up repeatedly in discussions, so in 2018 I sat
    down to investigate the issue. After a while I had a paper design,
    but had my doubts that it is worth implementing it. I let Bernd
    Paysan read the paper, and he came up with further simplifications and implemented the result; the changes were so deep that I had to mostly
    rewrite the paper, resulting in our EuroForth 2018 paper
    [ertl&paysan18]. And Bernd embraced using the resulting closures.

    I still had my doubts about whether one really needs that, as I had
    not found a short example that showed a clear advantage over the
    alternatives. I asked Niklaus Wirth, who had kept access to outer
    locals in his languages for many decades, but his answer was that he
    finally removed that feature from Oberon 07 in 2013, and he did not
    provide such an example, either.

    Finally, such a usage was found by Bernd Paysan: He had implemented a
    variant of the actor model
    <https://gforth.org/manual/Message-queues.html> (inspired by Heinz
    Schnitter's Open Network Forth):

    One task sends a message consisting of an xt to another task, and the
    other task then executes it. But sending just an xt without any data
    is not very useful, so one could also send integers, strings, etc.
    The sender would send the data and then the xt, and the receiving task
    would push the data on the stack, and then execute the xt. However,
    several tasks can send messages to one task at the same time, so there
    was some additional twist to avoid mixing the parts of a message of
    one task with the parts of a message of another task. With closures
    that all became unnecessary: The data is part of the passed xt.

    Another development was pure-stack closures.

    But none of this existed when quotations were accepted for
    standardization.

    @InProceedings{ertl&paysan18,
    author = {M. Anton Ertl and Bernd Paysan},
    title = {Closures --- the {Forth} way},
    crossref = {euroforth18},
    pages = {17--30},
    url = {https://www.complang.tuwien.ac.at/papers/ertl%26paysan.pdf},
    url2 = {http://www.euroforth.org/ef18/papers/ertl.pdf},
    slides-url = {http://www.euroforth.org/ef18/papers/ertl-slides.pdf},
    video = {https://wiki.forth-ev.de/doku.php/events:ef2018:closures},
    OPTnote = {refereed},
    abstract = {In Forth 200x, a quotation cannot access a local
    defined outside it, and therefore cannot be
    parameterized in the definition that produces its
    execution token. We present Forth closures; they
    lift this restriction with minimal implementation
    complexity. They are based on passing parameters on
    the stack when producing the execution token. The
    programmer has to explicitly manage the memory of
    the closure. We show a number of usage examples.
    We also present the current implementation, which
    takes 109~source lines of code (including some extra
    features). The programmer can mechanically convert
    lexical scoping (accessing a local defined outside)
    into code using our closures, by applying assignment
    conversion and flat-closure conversion. The result
    can do everything one expects from closures,
    including passing Knuth's man-or-boy test and living
    beyond the end of their enclosing definitions.}
    }

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Thu Feb 6 19:15:11 2025
    From Newsgroup: comp.lang.forth

    Another aspect:

    Once I had read/write access to outer locals from within
    quotations (or nested functions) I found that I was using
    it more and more for code organisation i.e. encapsulation of
    factored code segments.

    In 'normal' Forth, factorization tends to clutter up the
    current compilation wordlist.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Feb 7 10:36:47 2025
    From Newsgroup: comp.lang.forth

    On 7/02/2025 4:20 am, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    On 7/02/2025 12:59 am, minforth wrote:
    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:
    AFAIR 200x nested definitions were justified on the grounds named
    definitions were neither needed nor wanted

    Really? There's a proposal to eliminate named definitions? That's
    news to me.

    I didn't but clearly those that argued for quotations did.

    There are cases where you need to pass an xt to some word, and where
    the xt does not merit a name, e.g.,
    ...

    There's a case for having NONAME: which has no name and must pass an xt.
    But that's not the same as saying there's a need for definitions without
    names.

    and access to external
    locals not necessary.

    It's more that anything proper is pretty hard to implement and there
    was not enough demand for that nor existing practice that anybody
    wanted to propose for standardization.

    This only strengthened my view forth quotations had nothing to offer but namelessness. If want to hide names of definitions I no longer need to reference I have BEHEAD for that. Such facility has existed in forths
    long before the idea of quotations popped up on c.l.f.


    However, the topic came up repeatedly in discussions, so in 2018 I sat
    down to investigate the issue. After a while I had a paper design,
    but had my doubts that it is worth implementing it. I let Bernd
    Paysan read the paper, and he came up with further simplifications and implemented the result; the changes were so deep that I had to mostly
    rewrite the paper, resulting in our EuroForth 2018 paper
    [ertl&paysan18]. And Bernd embraced using the resulting closures.

    I still had my doubts about whether one really needs that, as I had
    not found a short example that showed a clear advantage over the alternatives. I asked Niklaus Wirth, who had kept access to outer
    locals in his languages for many decades, but his answer was that he
    finally removed that feature from Oberon 07 in 2013, and he did not
    provide such an example, either.

    Finally, such a usage was found by Bernd Paysan: He had implemented a
    variant of the actor model
    <https://gforth.org/manual/Message-queues.html> (inspired by Heinz Schnitter's Open Network Forth):

    One task sends a message consisting of an xt to another task, and the
    other task then executes it. But sending just an xt without any data
    is not very useful, so one could also send integers, strings, etc.
    The sender would send the data and then the xt, and the receiving task
    would push the data on the stack, and then execute the xt. However,
    several tasks can send messages to one task at the same time, so there
    was some additional twist to avoid mixing the parts of a message of
    one task with the parts of a message of another task. With closures
    that all became unnecessary: The data is part of the passed xt.

    Another development was pure-stack closures.

    But none of this existed when quotations were accepted for
    standardization.
    ...

    Interesting but what are you saying - that quotations as we have them
    are little more than a gimmick?

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Fri Feb 7 10:20:40 2025
    From Newsgroup: comp.lang.forth

    Where does this self-limiting backwardness come from?

    Virtually all modern embedded devices communicate with
    their outside world, and multitasking comes naturally.
    On the software side, closures can be a very helpful
    tool for communication and task management.

    So virtually all modern programming languages support
    closures (albeit with subtle nuances). I think a modern
    Forth should not be closed to modern programming concepts.
    DOS is finally history.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Feb 7 11:50:17 2025
    From Newsgroup: comp.lang.forth

    In article <392b236c4183716c5db29d3d8ae07e33@www.novabbs.com>,
    minforth <minforth@gmx.net> wrote:
    On Thu, 6 Feb 2025 11:11:28 +0000, albert@spenarnc.xs4all.nl wrote:

    With my enhanced [ ] pair, you can introduce whatever local
    widgets, in particular objects, you choose.

    The goal of language design is not to overload with features

    But haven't you overloaded the old [ ] with new features now? ;-)

    Or have I eliminated an unexpecte restriction?

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Feb 7 11:56:08 2025
    From Newsgroup: comp.lang.forth

    In article <53de9d9c27593c926215da4fb41e682f@www.novabbs.com>,
    minforth <minforth@gmx.net> wrote:
    There is indeed a restriction in standard §3.4:

    "A program shall not attempt to nest compilation of definitions.
    During the compilation of the current definition, a program
    shall not execute any defining word, :NONAME, or any definition
    that allocates dictionary data space."

    However because local names are not compiled into dictionary data
    space, but use their own transient dictionary entries, which
    disappear after compilation, this restriction as of $3.4 does not
    apply to embedded functions emulated by xt-locals, aka
    defer-flavoured locals.

    This is hypocritical. You want local, i.e. nested words, it is
    forbidden by the standards, now you implement it differently and
    maintain you abide by the standard.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Fri Feb 7 12:03:34 2025
    From Newsgroup: comp.lang.forth

    In article <3955434636b2a293c6a9c6d726ff6eae@www.novabbs.com>,
    minforth <minforth@gmx.net> wrote:
    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:

    minforth@gmx.net (minforth) writes:
    On Tue, 4 Feb 2025 12:26:26 +0000, albert@spenarnc.xs4all.nl wrote:
    Remark that is doesn't introduce any unfamiliar syntax,
    only does away with "Forth shall not nested definitions"
    (Says who?)

    Given that a Forth system supports quotations and xt-locals,
    nested definitions are easy to implement.

    You mean:

    : foo [: ." xyz" ;] {: xt: bar :} bar ;

    Sure, you then get a local that behaves similar to a nested
    definition, but I don't think anyone would want to do that.

    Yes, that's the mechanism. Actually I use it with some syntactic
    sugar for better readability:

    : foo
    <: bar ." xyz" ;>
    bar
    ;
    You mean
    : foo
    [ : bar ." xyz" ; ]
    bar
    ;

    I find this quite handy, since upvalues (locals within foo's
    context) are accessible from within bar.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Fri Feb 7 12:21:35 2025
    From Newsgroup: comp.lang.forth

    On Fri, 7 Feb 2025 11:03:34 +0000, albert@spenarnc.xs4all.nl wrote:
    Yes, that's the mechanism. Actually I use it with some syntactic
    sugar for better readability:

    : foo
    <: bar ." xyz" ;>
    bar
    ;

    You mean
    : foo
    [ : bar ." xyz" ; ]
    bar
    ;

    No I don't. My
    <: bar creates a local
    whereas your
    [ : bar seems to create a dictionary entry
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Fri Feb 7 17:50:02 2025
    From Newsgroup: comp.lang.forth

    minforth <minforth@gmx.net> wrote:

    However because local names are not compiled into dictionary data
    space, but use their own transient dictionary entries, which


    -- The goal then is nesting a definition to space outside of the
    -- dictionary. Using what's at hand, Toad version of Wil Baden's local
    -- macros:
    : foo
    [ '." xyz"' /mm: bar ]
    mm bar
    ;

    -- executing the nested code from the parent word
    i. foo --> xyz

    -- executing the code after the parent word has terminated.
    i. mm bar --> xyz

    -- Can also pass value to the local definition
    : foo
    '+ mmx: bardat' eval
    %'mm bardat ." xyz: " .' /mm: bar% eval
    'mm bar' eval
    ;

    i. 40 2 foo --> xyz: 42
    i. mm bar --> xyz: 42
    --
    me

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Fri Feb 7 18:09:57 2025
    From Newsgroup: comp.lang.forth

    On Thu, 6 Feb 2025 17:06:59 +0000, Anton Ertl wrote:

    minforth@gmx.net (minforth) writes:
    : foo
    <: bar ." xyz" ;>
    bar
    ;

    I find this quite handy, since upvalues (locals within foo's
    context) are accessible from within bar.

    Do you implement proper static scoping? I.e., does your system pass
    the man-or-boy test. What about returning xts that reference outer
    locals, e.g.:

    : n+ ( n -- xt ) {: n :} [: n + ;] ;
    5 n+ constant 5+
    3 5+ execute .
    7 5+ execute .

    As I said, I don't have proper scoping, as needed for closures
    (current MinForth only captures the outer context once, so it
    does not work with multiple instances)

    However, does this work in gforth?

    : n+ ( n -- xt ) {: n :} [: n + ;] ;
    5 n+ constant 5+
    10 n+ constant 10+ ( 2nd instance )
    2 5+ . ( 7 )
    2 10+ . ( 12 )
    3 5+ . ( 8 )
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Feb 8 08:43:12 2025
    From Newsgroup: comp.lang.forth

    On 7/02/2025 9:20 pm, minforth wrote:
    Where does this self-limiting backwardness come from?

    Virtually all modern embedded devices communicate with
    their outside world, and multitasking comes naturally.
    On the software side, closures can be a very helpful
    tool for communication and task management.

    So virtually all modern programming languages support
    closures (albeit with subtle nuances). I think a modern
    Forth should not be closed to modern programming concepts.
    DOS is finally history.

    Or the need is largely manufactured and languages copy each other
    so as to appear 'modern and fully-featured'. This occurred even in
    the days of DOS when PC magazines reviewed and compared compilers.
    Vendors knew very well that the more frills they could list, the
    more likely the sale. Never mind the actual utility. This is, of
    course, true for all consumer products.

    https://groups.google.com/g/comp.lang.forth/c/x8hUOj1MetU/m/uxqag5NrOo0J

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Feb 8 11:06:27 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    However, does this work in gforth?

    : n+ ( n -- xt ) {: n :} [: n + ;] ;
    5 n+ constant 5+
    10 n+ constant 10+ ( 2nd instance )
    2 5+ . ( 7 )
    2 10+ . ( 12 )
    3 5+ . ( 8 )

    : n+ ( n -- xt ) [{: n :}d n + ;] ;
    5 n+ constant 5+-xt
    10 n+ constant 10+-xt
    2 5+-xt execute . \ output: 7
    2 10+-xt execute . \ output: 12
    3 5+-xt execute . \ output: 8

    The :}D means that the closure data is stored in the dictionary; there
    is also :}L (for locals, deallocated when the surrounding definition
    is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap, deallocated right after the first (and only) execution).

    For the common cases of passing one cell or one double, or one FP
    value to a closure, there are also pure-stack closures:

    : n+ ( n -- xt ) [n:d + ;] ;

    works just like the locals-using N+ above. We have several numbers
    [T:A where T is the type (N for cell, D for double, F for float), and
    A is the allocation (L for local, D for dictionary, H for heap,
    currently no H1).

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sat Feb 8 11:41:32 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    On 7/02/2025 4:20 am, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    On 7/02/2025 12:59 am, minforth wrote:
    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:
    AFAIR 200x nested definitions were justified on the grounds named
    definitions were neither needed nor wanted

    Really? There's a proposal to eliminate named definitions? That's
    news to me.

    I didn't but clearly those that argued for quotations did.

    They did what? Make a proposal for eliminating named definitions?
    Where can I find that proposal? I was one of the proposers of
    quotations, so I certainly argued for them, and I am completely
    unaware of a proposal like you claim, neither from me, nor Alex
    McDonald (the first proposer of quotations), nor of anybody else
    arguing for quotations. Please present evidence of such a proposal.

    There's a case for having NONAME: which has no name and must pass an xt.

    Let's look at an example from the proposal:

    : hex. ( u -- )
    base @ >r
    [: hex u. ;] catch
    r> base ! throw ;

    There is no good way for replacing the quotation here with NONAME:, so
    NONAME: is a red herring.

    But that's not the same as saying there's a need for definitions without >names.

    "There's a need for definitions without names" is something completely different than "named definitions were neither needed nor wanted".

    And certainly :NONAME is there because there is a use for colon
    definitions without names. Whether these uses constitute needs is the question; they often can be replaced relatively easily by using named definitions. That's also the case for quotations. One could replace
    the definition above with:

    : hex.-helper ( u -- )
    hex u. ;

    : hex. ( u -- )
    base @ >r
    ['] hex.-helper catch
    r> base ! throw ;

    But would the result be easier to read, write, understand, or consume
    fewer resources? No.

    This only strengthened my view forth quotations had nothing to offer but >namelessness.

    They also offer nesting.

    If want to hide names of definitions I no longer need to
    reference I have BEHEAD for that.

    Let's see if this is ang better:

    | : hex.-helper ( u -- )
    hex u. ;

    : hex. ( u -- )
    base @ >r
    ['] hex.-helper catch
    r> base ! throw ;

    Not at all.

    Interesting but what are you saying - that quotations as we have them
    are little more than a gimmick?

    Let's see what that means; according to <https://en.wikipedia.org/wiki/Gimmick>:

    |A gimmick is a novel device or idea designed primarily to attract
    |attention or increase appeal, often with little intrinsic value.[1][2]
    |When applied to retail marketing, it is a unique or quirky feature
    |designed to make a product or service "stand out" from its
    |competitors.

    It is certainly intended to increase the appeal, but not primarily.
    It's not a unique or quirky feature, many other languages have nested
    nameless definitions.

    And Forth has had them too, and some posters love to present the use
    of return-stack manipulations to turn code pieces into nameless
    definitions that are then called in another context, without any
    protest from you. I think Hans Bezemer does it in the video that he
    advertised in the start of this thread (at least that's what the gist
    of the discussion here seems to indicate; I usually don't watch
    videos). One example is from the quotations proposal:

    : foo bar list> bla blub ;

    where the part after LIST> is a separate definition that is called
    once for every element in the list. There is even such a word in
    standard Forth (since Forth-79):

    : D A does> B ;

    Here the "B ;" is a separate definition (it's even specified that way
    in Forth-94 f.) that is called whenever another word C to which the
    DOES> has been applied is called.

    The LIST>-like definition splitting has several disadvantages:

    1) It's not obvious when reading the code that some arbitrary word
    splits a definition in that way.

    2) There is no way to continue the original definition after the
    LIST>-like word. E.g., the proposal contains the example

    : dofield ( -- )
    does> ( name execution: addr1 -- addr2 )
    @ + ;

    : dozerofield ( -- )
    immediate
    does> ( name execution: -- )
    drop ;

    : field ( align1 offset1 align size "name" -- align2 offset2 )
    \ name execution: addr1 -- addr2
    2 pick >r \ this uglyness is just for optimizing with dozerofield
    create-field
    r> if \ offset<>0
    dofield
    else
    dozerofield
    then ;

    Here the need for the separate words DOFIELD and DOZEROFIELD comes
    from the fact that there is no standard way to return to the
    original definition after the DOES>. The quotations proposal
    <http://www.forth200x.org/quotations.txt> contains a variant that
    encloses DOES> in quotations, but I find it even nicer to use
    SET-DOES> which takes an xt and makes C (the defined word) execute
    the xt. With that the example becomes:

    : field ( align1 offset1 align size "name" -- align2 offset2 )
    \ name execution: addr1 -- addr2
    2 pick >r \ this uglyness is just for optimizing with dozerofield
    create-field
    r> if \ offset<>0
    [: @ + ;] set-does>
    else
    immediate ['] drop set-does>
    then ;

    3) LIST> and similar words are implemented using return-address
    manipulation, which has problems with inlining and tail-call
    elimination. Either you do not implement inlining and tail-call
    elimination, or implement them only in a restricted way (incurring
    complications for determining whether you can use them), or you
    replace the use of LIST> with ways that do not use return-address
    manipulations.

    Users could have written the FOO example above as

    : foo-helper bla blub ;

    : foo bar ['] foo-helper map-list ;

    since at least Forth-83, but apparently they found the need for an
    out-of-line definition repulsing enough that they accepted the
    disadvantages of going for LIST>. With quotations, they can write
    the helper inline without the disadvantages:

    : foo bar [: bla blub ;] map-list ;

    And we certainly have a lot of uses of [: in Gforth.

    If you prefer to program without quotations, that's fine. If you
    don't want to implement them in your system, your system can still
    be standard (if you care about that); quotations are optional. But
    I usually don't brake for deprived systems when I program.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Sat Feb 8 12:31:45 2025
    From Newsgroup: comp.lang.forth

    Thanks, that makes sense. Each call to the outer function
    creates a data record for (the contexts of) each of its inner
    closure(s). The context records need to be managed somehow.

    Personally, I do not need more than the limited functionality
    that MinForth now provides. But I have a good idea how to
    extend it to full closures whenever the need arises in the
    future. That is, perhaps never... ;-)
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Feb 9 12:13:57 2025
    From Newsgroup: comp.lang.forth

    On 8/02/2025 10:41 pm, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    On 7/02/2025 4:20 am, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    On 7/02/2025 12:59 am, minforth wrote:
    On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:
    AFAIR 200x nested definitions were justified on the grounds named
    definitions were neither needed nor wanted

    Really? There's a proposal to eliminate named definitions? That's
    news to me.

    I didn't but clearly those that argued for quotations did.

    They did what? Make a proposal for eliminating named definitions?
    Where can I find that proposal? I was one of the proposers of
    quotations, so I certainly argued for them, and I am completely
    unaware of a proposal like you claim, neither from me, nor Alex
    McDonald (the first proposer of quotations), nor of anybody else
    arguing for quotations. Please present evidence of such a proposal.

    Let's not play semantics. Quotations are promoting nameless definitions.

    There's a case for having NONAME: which has no name and must pass an xt.

    Let's look at an example from the proposal:

    : hex. ( u -- )
    base @ >r
    [: hex u. ;] catch
    r> base ! throw ;

    There is no good way for replacing the quotation here with NONAME:, so NONAME: is a red herring.

    When was it necessary CATCH should operate on nameless definitions? The rationale for :NONAME was given in the ANS document. I see nothing of
    value in the example you quote.

    This only strengthened my view forth quotations had nothing to offer but
    namelessness.

    They also offer nesting.

    They offer confusion since there's no name. What language do you know where nested definitions are nameless? In Minforth's recent example he named the quotation. The only reason I can think is because a name made it readable!

    I have used :NONAME and found it useful. It's by no means an everyday thing - indeed it's the exception. I can't say the same about quotations - which strike
    me as being wrong in every way, not least because they are intended to feature prominently, stuffed in one's face. I don't understand the appeal at all.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sat Feb 8 23:07:11 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    Thanks, that makes sense. Each call to the outer function
    creates a data record for (the contexts of) each of its inner
    closure(s). The context records need to be managed somehow.

    Most languages with closures also have garbage collection, or anyway scope-controlled deallocation like in C++. It may not be obvious, but
    closures are sort of the same thing as OOP, just viewed from a different
    angle. Storage for the internal data of OOP instances has to be managed
    in about the same way.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sat Feb 8 23:41:38 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    quotations ... strike me as being wrong in every way, not least
    because they are intended to feature prominently, stuffed in one's
    face. I don't understand the appeal at all.

    I never got the impression they were supposed to be so prominent, though
    I guess one could program in a style that uses them heavily. My first
    Forth program used a lot of XT's but in retrospect, it was rather
    unidiomatic.

    The following sort of follows an idiom for Python GUI programs. You
    have a function MAKE-BUTTON that puts a button on the screen. The
    button has a label, and it calls a function when you press it. This
    is using the notation from Anton's post but I haven't tested it.

    : make-button ( a u xt -- ) ... ;
    \ a u is the label, xt is the action

    Now you want to draw buttons for a numeric keypad:

    : make-action ( n -- xt ) [n:d ." You pressed " . ] ;
    : make-label ( n -- a u ) \ make a string like "5" in the dictionary
    here { a } 1 chars allot '0' + a c! a 1 ;

    : keypad ( -- ) 10 0 do
    i make-label i make-action make-button
    loop ;

    Now there will be buttons labelled "0", "1", ... "9", and and when you
    press one, it will print "you pressed 5" or whatever for that button.

    I think the idiomatic old-school Forth alternative to this would be an
    OOP-like approach, but the above is probably more concise, and to some
    of us more intuitive.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Sun Feb 9 08:18:41 2025
    From Newsgroup: comp.lang.forth

    On Sun, 9 Feb 2025 7:07:11 +0000, Paul Rubin wrote:

    minforth@gmx.net (minforth) writes:
    Thanks, that makes sense. Each call to the outer function
    creates a data record for (the contexts of) each of its inner
    closure(s). The context records need to be managed somehow.

    Most languages with closures also have garbage collection, or anyway scope-controlled deallocation like in C++. It may not be obvious, but closures are sort of the same thing as OOP, just viewed from a different angle. Storage for the internal data of OOP instances has to be managed
    in about the same way.

    I found a good article that starts with an anecdote about Anton :-) https://kidneybone.com/c2/wiki/ClosuresAndObjectsAreEquivalent
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Feb 9 21:03:48 2025
    From Newsgroup: comp.lang.forth

    On 9/02/2025 6:41 pm, Paul Rubin wrote:
    dxf <dxforth@gmail.com> writes:
    quotations ... strike me as being wrong in every way, not least
    because they are intended to feature prominently, stuffed in one's
    face. I don't understand the appeal at all.

    I never got the impression they were supposed to be so prominent, though
    I guess one could program in a style that uses them heavily.

    IMO it does nothing for readability to see a definition interrupted by another. My reaction is one of WTF.

    My first
    Forth program used a lot of XT's but in retrospect, it was rather unidiomatic.

    The following sort of follows an idiom for Python GUI programs. You
    have a function MAKE-BUTTON that puts a button on the screen. The
    button has a label, and it calls a function when you press it. This
    is using the notation from Anton's post but I haven't tested it.

    : make-button ( a u xt -- ) ... ;
    \ a u is the label, xt is the action

    Now you want to draw buttons for a numeric keypad:

    : make-action ( n -- xt ) [n:d ." You pressed " . ] ;
    : make-label ( n -- a u ) \ make a string like "5" in the dictionary
    here { a } 1 chars allot '0' + a c! a 1 ;

    : keypad ( -- ) 10 0 do
    i make-label i make-action make-button
    loop ;

    Now there will be buttons labelled "0", "1", ... "9", and and when you
    press one, it will print "you pressed 5" or whatever for that button.

    I think the idiomatic old-school Forth alternative to this would be an OOP-like approach, but the above is probably more concise, and to some
    of us more intuitive.

    I don't understand make-action at all. What is it meant to be doing?
    Call me boring but I don't like inventing new syntax only to have to
    re-learn what it does when I have to come back and maintain it. Not
    sure if it applies to yours but ANS A.6.2.0455 gives an example of a table
    of code fragments using :NONAME. IMO such instances are rare enough to
    not require sugar-coating. I'm aware of quotations being used in DOES>
    code, words having multiple xt's etc but to me this is the antithesis of
    Forth - the opposite of being simple.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sun Feb 9 02:36:04 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    IMO it does nothing for readability to see a definition interrupted by another. My reaction is one of WTF.

    Maybe it looks weird in Forth, but similar things were present in
    languages as old as Fortran, which had "statement functions" (idk when
    those were introduced though). Algol had them, and lambda calculus
    (invented in the 1920's, before computers existed) had them. It's not inherently bad, though it can make code confusing if over-used. node.js
    uses the style heavily in a deeply nested and painful way.

    : make-action ( n -- xt ) [n:d ." You pressed " . ] ;
    I don't understand make-action at all. What is it meant to be doing?

    Imagine this function:

    : action-5 ( -- ) ." you pressed 5" ;

    That does the obvious thing: prints a fixed message, nothing else.
    Similarly you want action-1, action-2, and so on.

    How to generalize that? How about just having something that takes
    a numeric argument, and gives you an xt that runs that action?

    : make-action-n ( n -- xt ) ( need some magic here! ) ... ;

    So, "5 make-action-n" gives an xt that is equivalent to ' action-5,
    but you can make independent xt's for other values of n.

    That's what I called make-action in the example I showed, and for the
    "magic" it used a quotation. Maybe there is some reasonably easy
    alternative way to do the same thing in traditional Forth. The only
    ones that occur to me right now are pretty messy though.

    Call me boring but I don't like inventing new syntax only to have to

    Well, it's a one-time addition of new syntax, not something re-learned
    in every new program. Like 'x' is new syntax for [char] x, but once
    you've used it a few times you remember it and it seems to me like an improvement.

    So are quotations worth it for Forth? I don't know. I see some uses
    for them but I'd tend to say that style is more common in GC'd
    languages.

    the antithesis of Forth - the opposite of being simple.

    Forth is simple in some ways, complicated (or at least non-intuitive) in
    others ;).
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Sun Feb 9 14:35:23 2025
    From Newsgroup: comp.lang.forth

    On Sun, 9 Feb 2025 10:36:04 +0000, Paul Rubin wrote:

    So are quotations worth it for Forth? I don't know. I see some uses
    for them but I'd tend to say that style is more common in GC'd
    languages.

    Forth quotations are embedded anonymous functions. They
    produce a single execution token on the stack. No GC required.

    Forth closures are not standard. But generally spoken, closures
    are single-function aka one-shot objects. So gforth-specific
    closures offer several ways to free used memory after use.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Feb 9 15:45:00 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> writes:
    What language do you know where
    nested definitions are nameless?

    Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
    longer list can be found at <https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Feb 9 15:54:29 2025
    From Newsgroup: comp.lang.forth

    Paul Rubin <no.email@nospam.invalid> writes:
    It may not be obvious, but
    closures are sort of the same thing as OOP, just viewed from a different >angle.

    At least that's what the fans of languages claim that have only one or
    the other. And Forth has had ;CODE and DOES> very early on, and those
    who don't have objects or closures claim that DOES> is sort of the
    same as OOP and closures, just viewed from a different angle.

    Yet we found it fruitful to add object-oriented extensions in various
    Forth systems, and we find it fruitful to add closures in Gforth.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sun Feb 9 09:55:29 2025
    From Newsgroup: comp.lang.forth

    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    The :}D means that the closure data is stored in the dictionary; there
    is also :}L (for locals, deallocated when the surrounding definition
    is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap, deallocated right after the first (and only) execution).

    This is pretty cool, but it looks like quotations within the closure
    aren't allowed to access the closure's locals, using them as OOP-like
    state. In the current Gforth git snapshot:

    : x [{: n :}d [: n 1+ dup to n ;] ;]h 0 execute ;

    gives:

    *the terminal*:26:30: error: Unsupported operation
    : x [{: n :}d [: n 1+ dup to >>>n<<< ;] ;]h 0 execute ;

    This is an attempt to make a counting function, like in Scheme:

    (define (x)
    ((lambda (n)
    (lambda ()
    (set! n (+ 1 n))
    n)) 0))

    (define a (x))

    (a) ; 1
    (a) ; 2, etc.

    It would be interesting if your conservative gc could be made reliable
    and included with gforth, and then another suffix could be added to put
    closure locals in the gc'd heap. "Reliable" = scan the return and
    locals stacks, via suitable extensions added to GC. Also in a threaded
    program I guess it would have to stop any threads that shared a GC'd
    heap during collection of that heap.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Feb 9 19:54:55 2025
    From Newsgroup: comp.lang.forth

    In article <2025Feb8.124132@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    <SNIP>
    "There's a need for definitions without names" is something completely >different than "named definitions were neither needed nor wanted".

    I see it reversed, and view { } (anonymous code sequence) as fundamental. Assume (CREATE) "name" that creates a named dictionary header and
    leaves it address. This is general building block for e.g. VARIABLE
    CONSTANT : .
    Assume { } that compiles and leaves an executable token.
    Assume LINK-IN that links in an nt into the current wordlist.

    Then : can be defines as
    : : (CREATE) POSTPONE { ; \ Leaves "name token" , start compilation.
    : ; POSTPONE } OVER >R
    >CFA @ SWAP >CFA ! ( nt nt-temp -- ) \ Copy behaviour "code"
    R> ( nt , left by : ) LINK-IN ; IMMEDIATE

    There is no "need" for definition without "name", there is only an
    underlying concept that is more fundamental than the concepts like
    execution token, name token, definition or what have you.

    - anton

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Sun Feb 9 20:13:12 2025
    From Newsgroup: comp.lang.forth

    In article <2025Feb9.164500@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    dxf <dxforth@gmail.com> writes:
    What language do you know where
    nested definitions are nameless?

    Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
    longer list can be found at ><https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.

    In algol 68 the function is

    proc add := (int x, int y) int : x+y; 1)

    You have a symbolic reference add where a function is filled in.
    Lateron you can reassign the function add with a "function denotation"
    (int a, int b) int : a-b;

    [But the "(int x, int y) int " signature sticks.
    Formally it is an abbreviation of
    proc add (int x, int y) int := (int x, int y) int : x+y; ]

    This is the insight that I wanted to convey that the
    function denotation is fundamental, and the name is incidental.

    - anton

    Groetjes Albert

    1) Normally you use = instead of :=. Then you cannot change assign
    to add.
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Sun Feb 9 19:15:29 2025
    From Newsgroup: comp.lang.forth

    On Sun, 9 Feb 2025 17:55:29 +0000, Paul Rubin wrote:

    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    The :}D means that the closure data is stored in the dictionary; there
    is also :}L (for locals, deallocated when the surrounding definition
    is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap,
    deallocated right after the first (and only) execution).

    This is pretty cool, but it looks like quotations within the closure
    aren't allowed to access the closure's locals, using them as OOP-like
    state. In the current Gforth git snapshot:

    : x [{: n :}d [: n 1+ dup to n ;] ;]h 0 execute ;

    gives:

    *the terminal*:26:30: error: Unsupported operation
    : x [{: n :}d [: n 1+ dup to >>>n<<< ;] ;]h 0 execute ;

    This is an attempt to make a counting function, like in Scheme:

    (define (x)
    ((lambda (n)
    (lambda ()
    (set! n (+ 1 n))
    n)) 0))

    (define a (x))

    (a) ; 1
    (a) ; 2, etc.

    FWIW a single quotation-based counter in another Forth:

    MinForth 3.6 (32 bit)
    # defer ctr ok
    # : init { n } [: n 1+ dup to n ;] ; ok
    # 4 init is ctr ok
    # ctr . 5 ok
    # ctr . 6 ok
    # ctr . 7 ok
    #

    Generalisation would of course require closures and memory
    management after use.

    IOW read/write access to locals of the parent function opens
    up new possiblities in Forth - perhaps also an idea for gforth.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Sun Feb 9 14:30:28 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    FWIW a single quotation-based counter in another Forth:

    MinForth 3.6 (32 bit)
    # defer ctr ok
    # : init { n } [: n 1+ dup to n ;] ; ok
    # 4 init is ctr ok
    # ctr . 5 ok

    Questions:

    1) where does the storage cell for n live, after init has returned?

    2) what if you make more than one counter?

    3) why did you use defer instead of something like CONSTANT?

    thanks
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Sun Feb 9 23:08:22 2025
    From Newsgroup: comp.lang.forth

    Paul Rubin <no.email@nospam.invalid> writes:
    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    The :}D means that the closure data is stored in the dictionary; there
    is also :}L (for locals, deallocated when the surrounding definition
    is exited), :}H (heap, deallocated with FREE-CLOSURE), and :}H1 (heap,
    deallocated right after the first (and only) execution).

    This is pretty cool, but it looks like quotations within the closure
    aren't allowed to access the closure's locals

    Correct. You need to use a closure (and perform closure conversion
    and assignment conversion manually, if needed).

    This is an attempt to make a counting function, like in Scheme:

    (define (x)
    ((lambda (n)
    (lambda ()
    (set! n (+ 1 n))
    n)) 0))

    (define a (x))

    (a) ; 1
    (a) ; 2, etc.

    : x ( -- xt )
    here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;

    x alias a
    x alias b
    a . \ 1
    a . \ 2
    b . \ 1
    a . \ 3

    Given that you are using dictionary allocation, traditional Forth
    allocation for the mutable data is fine. There is also a syntax for
    allocating data in other locations, but you don't need it with
    dictionary allocation and traditional dictionary allocation is usually
    shorter. With that syntax the equivalent would be:

    : x ( -- xt )
    0 <{: w^ n :}d n ;> drop [{: n :}d n @ 1+ dup n ! ;] ;

    The other issue is that the value-flavoured local N or ADDR in the
    closure cannot be changed in a way that takes effect outside the
    closure. So you give an address to it, and use @, ! etc. to work on
    that (assignment conversion).

    It would be interesting if your conservative gc could be made reliable
    and included with gforth, and then another suffix could be added to put >closure locals in the gc'd heap.

    Yes. There is :}xt for passing an xt that performs the allocation.

    See <https://gforth.org/manual/Closures.html> for all of these topics.
    Or read the paper:

    @InProceedings{ertl&paysan18,
    author = {M. Anton Ertl and Bernd Paysan},
    title = {Closures --- the {Forth} way},
    crossref = {euroforth18},
    pages = {17--30},
    url = {https://www.complang.tuwien.ac.at/papers/ertl%26paysan.pdf},
    url2 = {http://www.euroforth.org/ef18/papers/ertl.pdf},
    slides-url = {http://www.euroforth.org/ef18/papers/ertl-slides.pdf},
    video = {https://wiki.forth-ev.de/doku.php/events:ef2018:closures},
    OPTnote = {refereed},
    abstract = {In Forth 200x, a quotation cannot access a local
    defined outside it, and therefore cannot be
    parameterized in the definition that produces its
    execution token. We present Forth closures; they
    lift this restriction with minimal implementation
    complexity. They are based on passing parameters on
    the stack when producing the execution token. The
    programmer has to explicitly manage the memory of
    the closure. We show a number of usage examples.
    We also present the current implementation, which
    takes 109~source lines of code (including some extra
    features). The programmer can mechanically convert
    lexical scoping (accessing a local defined outside)
    into code using our closures, by applying assignment
    conversion and flat-closure conversion. The result
    can do everything one expects from closures,
    including passing Knuth's man-or-boy test and living
    beyond the end of their enclosing definitions.}
    }

    Also in a threaded
    program I guess it would have to stop any threads that shared a GC'd
    heap during collection of that heap.

    That's a tough one. My current thinking is along the lines of a
    per-thread allocator and garbage-collector, with no heap-allocated
    data passed between threads. Then thread-unaware GCs are good enough.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Mon Feb 10 01:30:01 2025
    From Newsgroup: comp.lang.forth

    On Sun, 9 Feb 2025 22:30:28 +0000, Paul Rubin wrote:

    minforth@gmx.net (minforth) writes:
    FWIW a single quotation-based counter in another Forth:

    MinForth 3.6 (32 bit)
    # defer ctr ok
    # : init { n } [: n 1+ dup to n ;] ; ok
    # 4 init is ctr ok
    # ctr . 5 ok

    Questions:

    1) where does the storage cell for n live, after init has returned?

    2) what if you make more than one counter?

    3) why did you use defer instead of something like CONSTANT?

    thanks

    1) Briefly, details omitted: a copy of the locals stack frame of the
    outer function is inlined. Before execution of the quotation, this
    copy is inserted into the quotation's locals stack frame.

    2) Won't work because there is only one copy per quotation

    3) Convenience
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Feb 10 13:00:58 2025
    From Newsgroup: comp.lang.forth

    On 10/02/2025 2:45 am, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    What language do you know where
    nested definitions are nameless?

    Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
    longer list can be found at <https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.

    "The use of anonymous functions is a matter of style. Using them is never
    the only way to solve a problem; each anonymous function could instead be
    defined as a named function and called by name."

    So it's a style - a fashion statement.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Mon Feb 10 06:14:52 2025
    From Newsgroup: comp.lang.forth

    On Sun, 9 Feb 2025 23:08:22 +0000, Anton Ertl wrote:

    Paul Rubin <no.email@nospam.invalid> writes:
    ..
    This is an attempt to make a counting function, like in Scheme:

    (define (x)
    ((lambda (n)
    (lambda ()
    (set! n (+ 1 n))
    n)) 0))

    (define a (x))

    (a) ; 1
    (a) ; 2, etc.

    : x ( -- xt )
    here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;

    x alias a
    x alias b
    a . \ 1
    a . \ 2
    b . \ 1
    a . \ 3

    Hi,
    But I can do it like this:
    : ctr: create 0 , does> dup @ 1+ dup rot ! ; ok
    ctr: a
    ctr: b

    a . 1 ok
    b . 1 ok
    a . 2 ok
    b . 2 ok
    b . 3 ok

    So, what is the difference between the two definitions?

    - anton

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Mon Feb 10 07:19:05 2025
    From Newsgroup: comp.lang.forth

    melahi_ahmed@yahoo.fr (ahmed) writes:
    On Sun, 9 Feb 2025 23:08:22 +0000, Anton Ertl wrote:

    Paul Rubin <no.email@nospam.invalid> writes:
    ..
    This is an attempt to make a counting function, like in Scheme:

    (define (x)
    ((lambda (n)
    (lambda ()
    (set! n (+ 1 n))
    n)) 0))

    (define a (x))
    ...
    : x ( -- xt )
    here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;

    x alias a
    ...
    : ctr: create 0 , does> dup @ 1+ dup rot ! ; ok
    ctr: a
    ...
    So, what is the difference between the two definitions?

    One produces an xt, the other a named word; the latter is more
    convenient for the shown usage).

    But yes, for dictionary allocation Forth has had a way to associate
    data with a single action since very early on.

    If you want heap allocation (i.e., to be able to reclaim the memory
    when you no longer need the counter), you can do it with closures, but
    not with DOES>:

    : x ( -- addr xt )
    0 <{: w^ n :}H n ;> swap [{: n :}H n @ 1+ dup n ! ;] ;
    x
    dup execute . \ 1
    dup execute . \ 2
    x
    dup execute . \ 1
    free-closure free throw
    dup execute . \ 3
    free-closure free throw

    Instead of using the syntax for allocating the data above, one could
    also use heap allocation directly:

    : x ( -- addr xt )
    1 cells allocate throw 0 over ! dup [{: n :}H n @ 1+ dup n ! ;] ;

    Following the textbook spirit of Paul Rubin's example, you can have
    several closures working on the same data instance. E.g., let's
    separate the count-up and the read-out functions (back to dictionary allocation), and this time using pure-stack closures:

    : y ( -- xt-count xt-val )
    here 0 , dup [n:d 1 swap +! ;] swap [n:d @ ;] ;
    y
    dup execute . \ 0
    over execute
    dup execute . \ 1
    over execute
    over execute
    y
    dup execute . \ 0
    2swap
    dup execute . \ 3
    2drop 2drop

    You can also use DOES> for this effect, but it becomes longer and less efficient:

    : y-count ( addr "name" -- )
    create ,
    does> ( -- )
    @ 1 swap +! ;

    : y-val ( addr "name" -- )
    create ,
    does> ( -- u )
    @ @ ;

    : y ( "name1" "name2" -- )
    here 0 , dup y-count y-val ;

    y a-count a-val
    a-val . \ 0
    a-count
    a-val . \ 1
    a-count
    a-count
    y b-count b-val
    b-val . \ 0
    a-val . \ 3

    But, as mentioned below, the textbook examples of changing data in
    closures or DOES> words are rarely found in practice.

    About the <{: ... ;> syntax:

    The <{: ... ;> syntax becomes more useful if multiple data is located
    there; you could instead define a structure, allocate that, and access
    the fields, but defining a structure for a single usage is less
    convenient than the syntax above; OTOH, with the syntax above you have
    to pass all the addresses separately (and name them again in the
    closure), while you can just pass the address of the structure to the
    closure and then address the fields. So maybe the <{: ... ;> syntax is
    never really useful.

    The main reason why it is not used is not because alternative ways of
    achieving the same thing are preferred, but because we usually don't
    have uses of closures where the data changes. Not for closures, and
    not for DOES>. The common case is that we have some value that we
    want to associate with the code, and we do it at closure creation, and
    then do not change it. I.e., something like Paul Rubin's textbook
    example is a rare case in practice. And if the data is not changed,
    it can just be passed as value to the closures, no home location with
    an address necessary (and therefore no <{: ... ;>).

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From melahi_ahmed@melahi_ahmed@yahoo.fr (ahmed) to comp.lang.forth on Mon Feb 10 08:34:41 2025
    From Newsgroup: comp.lang.forth

    Thanks!
    It is a little bit complicated to me (for now).
    I'll study it and figure out how to use it.

    Thanks again.

    Ahmed

    --
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Mon Feb 10 08:37:37 2025
    From Newsgroup: comp.lang.forth

    Another use case (which I use a lot): higher oder functions
    like the classic map/filter/reduce and domain-specific ones.
    I have no idea how that could be done with CREATE .. DOES>
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From mhx@mhx@iae.nl (mhx) to comp.lang.forth on Mon Feb 10 09:20:00 2025
    From Newsgroup: comp.lang.forth

    If you want heap allocation (i.e., to be able to reclaim the memory
    when you no longer need the counter), you can do it with closures, but
    not with DOES>:

    You can just FORGET the word.

    -marcel
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Feb 10 14:40:05 2025
    From Newsgroup: comp.lang.forth

    In article <2025Feb10.081905@mips.complang.tuwien.ac.at>,
    Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
    melahi_ahmed@yahoo.fr (ahmed) writes:
    On Sun, 9 Feb 2025 23:08:22 +0000, Anton Ertl wrote:

    Paul Rubin <no.email@nospam.invalid> writes:
    ..
    This is an attempt to make a counting function, like in Scheme:

    (define (x)
    ((lambda (n)
    (lambda ()
    (set! n (+ 1 n))
    n)) 0))

    (define a (x))
    ...
    : x ( -- xt )
    here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;

    x alias a
    ...
    : ctr: create 0 , does> dup @ 1+ dup rot ! ; ok
    ctr: a
    ...
    So, what is the difference between the two definitions?

    One produces an xt, the other a named word; the latter is more
    convenient for the shown usage).

    But yes, for dictionary allocation Forth has had a way to associate
    data with a single action since very early on.

    Make that
    "
    Forth has had a way to associate
    data with a single action since very early on.
    "
    or more precise
    " Forth recipes combine code and data"

    Using underlying more primitive facilities in a Forth, one can define
    a recipe ("xt") that has no name, is not linked in a wordlist and sits
    in ALLOCATEd space and perform an action like x.
    (Admittedly, in a Forth that separates code and data it is more involved)

    This is a simple example to get a word `test floating in allocated space.
    (In ciforth example)
    ALLOC moves a word to the heap freeing the a freshly generated object
    that runs from ( addr --) to HERE. This doesn't switch DP, and assumes relocatable code.
    UNLINK-LATEST decouples the latest word from the dictionary.

    WANT >ALLOC UNLINK-LATEST
    INIT-ALLOC \ Use 1/4 of the dictionary space for heap.

    : test "hello" TYPE ;
    ' test UNLINK-LATEST \ decouple
    ALLOC \ move to heap
    WORDS \ to show that test has vanished
    .S \ The xt
    EXECUTE
    hello OK

    In the above example reclaiming memory is not harder than with
    any dynamically allocated memory.

    [This doesn't show how the data is coupled, but conveys hopefully
    a part of the idea.]

    <SNIP>

    But, as mentioned below, the textbook examples of changing data in
    closures or DOES> words are rarely found in practice.

    I totally agree on this. In 400+ euler problems I was never inclined
    to use this technique (if this counts for something ..)

    <SNIP>

    - anton
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Feb 10 14:45:12 2025
    From Newsgroup: comp.lang.forth

    In article <75f81945380192813776e3b0dd2ddec5@www.novabbs.com>,
    mhx <mhx@iae.nl> wrote:
    If you want heap allocation (i.e., to be able to reclaim the memory
    when you no longer need the counter), you can do it with closures, but
    not with DOES>:

    You can just FORGET the word.

    If you forego heap allocation, that is.
    If you combine heap allocation and FORGET/MARKERS and closures/DOES>
    it can be very tricky.


    -marcel
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Mon Feb 10 14:50:55 2025
    From Newsgroup: comp.lang.forth

    In article <9f5d42ff6471fb5bd1c209e39527b7cdf715546c@i2pn2.org>,
    dxf <dxforth@gmail.com> wrote:
    On 10/02/2025 2:45 am, Anton Ertl wrote:
    dxf <dxforth@gmail.com> writes:
    What language do you know where
    nested definitions are nameless?

    Just to name a few: Lisp, Smalltalk, Postscript, Joy, Factor. A much
    longer list can be found at
    <https://en.wikipedia.org/wiki/Anonymous_function#List_of_languages>.

    "The use of anonymous functions is a matter of style. Using them is never
    the only way to solve a problem; each anonymous function could instead be defined as a named function and called by name."

    So it's a style - a fashion statement.

    This remembers me of FORTRAN code long ago.

    print( sin(t*x))

    was too hard to understand.

    It is recommended to do:

    a = t*x
    b= sin(a)
    print(b)

    See also my post about the dispatch table for lisp in this thread.

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Mon Feb 10 09:21:46 2025
    From Newsgroup: comp.lang.forth

    mhx@iae.nl (mhx) writes:
    You can just FORGET the word.

    That also forgets any words that were defined later, I thought.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Mon Feb 10 11:21:59 2025
    From Newsgroup: comp.lang.forth

    anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
    : x ( -- xt )
    here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;

    Nice ;).

    : x ( -- xt )
    0 <{: w^ n :}d n ;> drop [{: n :}d n @ 1+ dup n ! ;] ;

    Why do you use <{: ... :}> instead of something like [{: ... :} ... ;]w ?

    another suffix could be added to put closure locals in the gc'd heap.
    Yes. There is :}xt for passing an xt that performs the allocation.
    See <https://gforth.org/manual/Closures.html> for all of these topics.

    Ah nice, I did see the mention of :}xt in the docs, but didn't connect
    that with garbage collection. It seems worth a mention. I saw the
    paper when it came out but should look at it again. I would say having
    to pass the allocator to the xt is a bit messy though there is probably
    a simple way to wrap it automatically.

    Also in a threaded program I guess it would have to stop any threads
    that shared a GC'd heap during collection of that heap.

    That's a tough one. My current thinking is along the lines of a
    per-thread allocator and garbage-collector, with no heap-allocated
    data passed between threads. Then thread-unaware GCs are good enough.

    Ergh, that adds a new layer of discipline required of the program,
    avoiding passing gc'd data between threads. For example, the :}h1
    allocator could leak memory you pass the xt to another thread and the
    receiver never calls it. So you might prefer to use the gc allocator,
    but then the message passing scheme breaks the heap-per-thread
    invariant.

    Erlang handles this by serializing and copying the closure from the
    sender's heap to the receiver's during message passing. Maybe gforth
    could get a library function that does something similar. Python and
    GHC don't attempt separate heaps per thread, and it's common in them to
    pass shared heap data between threads using message queues. The main convention you have to follow in Python is that any mutating objects
    must be owned by a single thread and not accessed by any others.
    Attempting to e.g. protect them with locks turns into a big mess.

    OTOH, if Gforth is going to use a copying approach, maybe it should go
    the full Erlang route and use multiple processes instead of Posix threads.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Tue Feb 11 10:21:57 2025
    From Newsgroup: comp.lang.forth

    Unfortunately, everything is very non-standard, as there is
    no multitasking wordset (for historical reasons?).
    A pity really, as co-operative multitasking existed very
    early on in Forth.
    Then it would be easier to have better discussions about
    coroutines (the original topic of this thread) or ownership
    of closure objects and different variants of GC.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paul Rubin@no.email@nospam.invalid to comp.lang.forth on Tue Feb 11 14:17:31 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    Unfortunately, everything is very non-standard, as there is
    no multitasking wordset (for historical reasons?).
    A pity really, as co-operative multitasking existed very
    early on in Forth.

    I had thought there wasn't enough agreement about the wordset to
    standardize it, and the same thing happened for cross development. But
    at least for multitasking, there is reasonable shared understanding
    about how it should work, at least in the cooperative case.

    Then it would be easier to have better discussions about coroutines
    (the original topic of this thread) or ownership of closure objects
    and different variants of GC.

    I think these fancy closures are mostly of interest to language geeks
    and not so much in the old-fashioned Forth spirit. Coroutines don't
    seem that important if you have multitasking. Anton's GC is great and I
    think cooperative multitasking wouldn't affect it much, if you don't
    mind the collection pauses. It would simply block during collection.

    The GC hazard we're discussing is when there are real preemptive threads
    and maybe multiple cores. This may also be reaching outside of Forth's traditional areas of effectiveness. Software transactional memory (STM)
    is another topic that should probably come up again. We haven't heard
    from Andrew Haley in a while though.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From albert@albert@spenarnc.xs4all.nl to comp.lang.forth on Wed Feb 12 13:49:48 2025
    From Newsgroup: comp.lang.forth

    In article <87wmdwunwk.fsf@nightsong.com>,
    Paul Rubin <no.email@nospam.invalid> wrote:
    minforth@gmx.net (minforth) writes:
    Unfortunately, everything is very non-standard, as there is
    no multitasking wordset (for historical reasons?).
    A pity really, as co-operative multitasking existed very
    early on in Forth.

    I had thought there wasn't enough agreement about the wordset to
    standardize it, and the same thing happened for cross development. But
    at least for multitasking, there is reasonable shared understanding
    about how it should work, at least in the cooperative case.

    Then it would be easier to have better discussions about coroutines
    (the original topic of this thread) or ownership of closure objects
    and different variants of GC.

    I think these fancy closures are mostly of interest to language geeks
    and not so much in the old-fashioned Forth spirit. Coroutines don't
    seem that important if you have multitasking. Anton's GC is great and I >think cooperative multitasking wouldn't affect it much, if you don't
    mind the collection pauses. It would simply block during collection.

    Look at python: they have decorators. In Forth this looks like:
    ' aap ' noot decorate
    Execute `aap (e.g. .S) before each invocation of `noot

    This works nicely with coroutines. In ciforth it is actually implemented.
    (also undecorated of course)

    In ciforth the canonical example is
    "
    { &i EMIT .S ;: &o EMIT .S } 'somethingbuggy decorated
    "
    The `;: ( `CO ) takes care that the second part is executed after each invocation of `somethingbuggy.
    Note that this is ideal for Heisenbug's, where you cannot insert testoutput because the bug disappears as soon as memory is shifted.

    Downplaying coroutines is an indication that you have not realised
    the potential.

    [I don't care much about closures, maybe the same applies to me
    about closures.]

    Groetjes Albert
    --
    Temu exploits Christians: (Disclaimer, only 10 apostles)
    Last Supper Acrylic Suncatcher - 15Cm Round Stained Glass- Style Wall
    Art For Home, Office And Garden Decor - Perfect For Windows, Bars,
    And Gifts For Friends Family And Colleagues.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From minforth@minforth@gmx.net (minforth) to comp.lang.forth on Wed Feb 12 22:30:18 2025
    From Newsgroup: comp.lang.forth

    On Tue, 11 Feb 2025 22:17:31 +0000, Paul Rubin wrote:

    minforth@gmx.net (minforth) writes:
    Unfortunately, everything is very non-standard, as there is
    no multitasking wordset (for historical reasons?).
    A pity really, as co-operative multitasking existed very
    early on in Forth.

    I had thought there wasn't enough agreement about the wordset to
    standardize it

    Likely dead or too little support: https://forth-standard.org/proposals/multi-tasking-proposal
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From anton@anton@mips.complang.tuwien.ac.at (Anton Ertl) to comp.lang.forth on Fri Feb 14 08:13:48 2025
    From Newsgroup: comp.lang.forth

    minforth@gmx.net (minforth) writes:
    On Tue, 11 Feb 2025 22:17:31 +0000, Paul Rubin wrote:

    minforth@gmx.net (minforth) writes:
    Unfortunately, everything is very non-standard, as there is
    no multitasking wordset (for historical reasons?).
    A pity really, as co-operative multitasking existed very
    early on in Forth.

    I had thought there wasn't enough agreement about the wordset to
    standardize it

    Likely dead or too little support: >https://forth-standard.org/proposals/multi-tasking-proposal

    The proposal has not proceeded to the point that there would be
    disagreement. Overall there seems to be a lot of commonality between
    systems, and standardization seems possible. It's just that there
    needs to be someone who makes a proposal. Andrew Haley started a
    proposal, but then there was not much progress and eventually he
    dropped out. Bernd Paysan was then asked to continue, but has not
    done anything yet. The main focus of his standards work at the moment
    is recognizers, and we all have other things to do, too.

    - anton
    --
    M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
    comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
    New standard: https://forth-standard.org/
    EuroForth 2023 proceedings: http://www.euroforth.org/ef23/papers/
    EuroForth 2024 proceedings: http://www.euroforth.org/ef24/papers/
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Tue Mar 11 16:24:42 2025
    From Newsgroup: comp.lang.forth

    Here's the simple locals paradigm using VALUEs. OTOH it's likely
    to be less portable than the VARIABLE-based one.

    : ;: >r ;

    : (local) ( x xt -- ) \ assume CREATE-based VALUEs
    r> -rot dup execute over 2>r >body ! ;: 2r> >body ! ;

    : LOCAL ( x "name" -- )
    ' postpone literal postpone (local) ; immediate

    \ behead (local) (local)

    \ Example
    8 value A 7 value B

    : divide ( a b -- ) local b local a
    a b / . cr ;

    15 3 divide a . b .

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Thu Mar 20 13:07:07 2025
    From Newsgroup: comp.lang.forth

    On 11-03-2025 06:24, dxf wrote:
    Here's the simple locals paradigm using VALUEs. OTOH it's likely
    to be less portable than the VARIABLE-based one.

    : ;: >r ;

    : (local) ( x xt -- ) \ assume CREATE-based VALUEs
    r> -rot dup execute over 2>r >body ! ;: 2r> >body ! ;

    : LOCAL ( x "name" -- )
    ' postpone literal postpone (local) ; immediate

    \ behead (local) (local)

    \ Example
    8 value A 7 value B

    : divide ( a b -- ) local b local a
    a b / . cr ;

    15 3 divide a . b .


    You'd be surprised. Actually, I did the same trick in my video, where I
    simply fed LOCAL the physical address of a VALUE.

    Now, in 4tH all variables are relative to a variable offset for
    technical reasons and hence have to be flagged accordingly - where
    strings are offset to a fixed offset and hence are compiled as absolute addresses.

    Why am I explaining all this? Because >BODY is the word in 4tH that
    converts a relative address of a VARIABLE/VALUE to an absolute one. And
    hence, it is applied here.

    Still, I can't compile your entire definition, because of ' and
    POSTPONE. ' only works in 4tH when directly followed by a name. POSTPONE
    has no meaning in 4tH, because nothing is executed while compiling. You
    can apply the preprocessor instead, though.

    But the major problem is that ' doesn't return an XT, but just a
    relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to
    accommodate those restrictions:

    : (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;

    Back ported to Gforth - it works!

    Gforth 0.7.9_20250101
    Authors: Anton Ertl, Bernd Paysan, Jens Wilke et al., for more type
    `authors'
    Copyright © 2025 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later
    <https://gnu.org/licenses/gpl.html>
    Gforth comes with ABSOLUTELY NO WARRANTY; for details type `license'
    Type `help' for basic help
    0 warnings ! ok
    : ;: >r ; ok
    : (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ; ok
    : LOCAL ( x "name" -- ) ' postpone literal postpone (local) ;
    immediate ok
    ok
    8 value A 7 value B ok
    ok
    : divide ( a b -- ) local b local a compiling
    a b / . cr ; ok
    ok
    15 3 divide a . b . 5
    8 7 ok

    Hans Bezemer




    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Mar 21 11:38:30 2025
    From Newsgroup: comp.lang.forth

    On 20/03/2025 11:07 pm, Hans Bezemer wrote:
    ...
    But the major problem is that ' doesn't return an XT, but just a relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to accommodate those restrictions:

    : (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;

    Back ported to Gforth - it works!
    ...

    Slightly smaller (for me) and not less portable. Thanks!

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Fri Mar 21 18:45:34 2025
    From Newsgroup: comp.lang.forth

    On 21/03/2025 11:38 am, dxf wrote:
    On 20/03/2025 11:07 pm, Hans Bezemer wrote:
    ...
    But the major problem is that ' doesn't return an XT, but just a relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to accommodate those restrictions:

    : (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;

    Back ported to Gforth - it works!
    ...

    Slightly smaller (for me) and not less portable. Thanks!

    The run-time code can be reduced further by relocating >BODY ...

    : (local) ( x adr -- ) r> -rot dup @ over 2>r ! ;: 2r> ! ;

    : LOCAL ( x "name" -- )
    ' >body postpone literal postpone (local) ; immediate


    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Fri Mar 21 13:27:45 2025
    From Newsgroup: comp.lang.forth

    On 21-03-2025 08:45, dxf wrote:
    On 21/03/2025 11:38 am, dxf wrote:
    On 20/03/2025 11:07 pm, Hans Bezemer wrote:
    ...
    But the major problem is that ' doesn't return an XT, but just a relative address. Without applying >BODY I can't retrieve the original address. So, in order to make this work, I have to redefine it to accommodate those restrictions:

    : (local) ( x xt -- ) r> -rot >body dup @ over 2>r ! ;: 2r> ! ;

    Back ported to Gforth - it works!
    ...

    Slightly smaller (for me) and not less portable. Thanks!

    The run-time code can be reduced further by relocating >BODY ...

    : (local) ( x adr -- ) r> -rot dup @ over 2>r ! ;: 2r> ! ;

    : LOCAL ( x "name" -- )
    ' >body postpone literal postpone (local) ; immediate

    That's essentially the trick I pulled when recreating the Forth-200x
    LOCALS. Under the hood the 4tH preprocessor created the global VALUES
    and then used this to transfer the address of the VALUES to LOCAL:

    : local r> swap dup >r @ >r ;: r> r> ! ;

    ( definition using locals)
    [UNDEFINED] a [IF] 0 value a [THEN]
    ['] a >BODY LOCAL
    TO a

    .. which has pretty much the same effect as your construct, but needs
    the 4tH preprocessor to be more involved.

    Nice test - I bet it wouldn't be too hard to implement at least part of
    the Forth-200x implementation ;-)

    Sometin' like define {:
    1. Parse a word;
    2. If not :} then create a (local);
    3. Repeat.

    Ok, this is horrible code, it needs the VALUES in reverse, but it works:

    : :} ;
    : {: begin ' dup ['] :} <> while >body postpone literal postpone (local) repeat drop ; immediate

    : test {: b a :} a b / ;

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sat Mar 22 10:26:45 2025
    From Newsgroup: comp.lang.forth

    On 21/03/2025 11:27 pm, Hans Bezemer wrote:
    ...
    Nice test - I bet it wouldn't be too hard to implement at least part of the Forth-200x implementation ;-)

    Sometin' like define {:
    1. Parse a word;
    2. If not :} then create a (local);
    3. Repeat.

    Ok, this is horrible code, it needs the VALUES in reverse, but it works:

    : :} ;
    : {: begin ' dup ['] :} <> while >body postpone literal postpone (local) repeat drop ; immediate

    : test {: b a :} a b / ;

    I'd just call that LOCAL| and be done. Can't say I ever found the syntax an annoyance. I appreciate it might not be ideal for doing Windows API calls...





    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Sat Mar 22 15:51:18 2025
    From Newsgroup: comp.lang.forth

    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .


    ( ENTER is the same as ';:' )
    : LOCAL ( x adr -- )
    r> -rot dup @ over 2>r ! ENTER 2r> ! ;

    \ prefixed '-' to indicate this word does a cut
    : -idiv ( n1 n2\0 -- n3 | n1 0 -- true )
    dup if /
    else 2drop true -CUT
    then
    ;

    : ?idiv ( n1 n2 -- n1/n2 false | <nothing> )
    CUT: -idiv ." Valid: " false
    ;

    42 variable a
    42 variable b

    : ?/ ( u1 u2 -- u1/u2 )
    a local b local
    b @ a @ ?idiv
    if ." Bogus! " 666 then .
    ;

    i. 100 5 ?/ --> Valid: 20
    i. a ? b ? --> 42 42
    i. 100 0 ?/ --> Bogus! 666
    i. a ? b ? --> 42 42

    forget ?/

    : ?/ ( u1 u2 -- u1/u2 )
    a local b local
    b @ a @ ' ?idiv ENTER
    if ." Bogus! " 666 then .
    ;

    i. 100 5 ?/ --> Valid: 20
    i. a ? b ? --> 42 42
    i. 100 0 ?/ --> Bogus! 666
    i. a ? b ? --> 42 42

    forget ?/

    : ?/ ( u1 u2 -- u1/u2 )
    a local b local
    b @ a @ (: cut: -idiv ." Valid: " false ;) ENTER
    if ." Bogus! " 666 then .
    ;

    i. 100 5 ?/ --> Valid: 20
    i. a ? b ? --> 42 42
    i. 100 0 ?/ --> Bogus! 666
    i. a ? b ? --> 42 42

    +echo
    -fin-

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Sun Mar 23 14:03:32 2025
    From Newsgroup: comp.lang.forth

    On 23/03/2025 2:51 am, sjack wrote:
    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .

    Does anyone have a reference/details for this anywhere as I can't seem to
    find anything?

    A possibly useful hit but the doc is locked away:

    https://doi.org/10.1145/165628.165637

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Mar 23 12:12:21 2025
    From Newsgroup: comp.lang.forth

    On 23-03-2025 04:03, dxf wrote:
    On 23/03/2025 2:51 am, sjack wrote:
    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .

    Does anyone have a reference/details for this anywhere as I can't seem to find anything?

    A possibly useful hit but the doc is locked away:

    https://doi.org/10.1145/165628.165637

    I was able to get it the "Aaron way" - but there is *no* definition here
    of CUT: and -CUT. This is all the code it contains (WARNING, copy and
    pasted from an image PDF file):

    : MSG ( i -> )
    R> DUP CELL+ SWAP @ 1+ 1
    DO ( i addr ) OVER I
    IF DUP COUNT TYPE THEN
    COUNT +
    LOOP >R DROP ;

    : ERRMSG
    MSG [ 3 ,
    ," file not found"
    ," r/o disk"
    ," wrong command format"
    ] CR ABORT ;


    2 CONSTANT CFL ( Code Field Length
    : :=
    ?COMP -2 ALLOT HERE @ [COMPILE]
    ['] CFL + , ; IMMEDIATE
    VECT N
    ( N := . is equivalent to ['] . TON )

    : (CALL) R> DUP 2+ >R @ >R ;
    : ENTER >R ;
    : : CREATE HIDE ] DOES> >R ;
    : (EXEC) R@ ! ;
    : EXECUTE COMPILE (EXEC) 0 , ; IMMEDIATE
    : CF! ( w cfa --) ! ;
    : LINK! ( w lf --) ! ;
    : N. BODY> >NAME .NAME ;
    : R> POSTPONE R> POSTPONE CELL+ ; IMMEDIATE
    : >R POSTPONE CELL- POSTPONE >R ; IMMEDIATE

    Hans Bezemer
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Sun Mar 23 12:25:27 2025
    From Newsgroup: comp.lang.forth

    On 23-03-2025 04:03, dxf wrote:
    On 23/03/2025 2:51 am, sjack wrote:
    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .

    Does anyone have a reference/details for this anywhere as I can't seem to find anything?

    A possibly useful hit but the doc is locked away:

    https://doi.org/10.1145/165628.165637

    Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt

    But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT:
    and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th

    It's code for a light weight stack. BTW, TRACKING is missing as well. It
    might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th

    : CUT: \ mark the beginning of the fragment to cut
    R> RP@ >L \ copy r-stack top addr. to L-stack
    BACK LDROP TRACKING \ delete this mark when backtracking
    >R ;
    : -CUT R> L> RP! >R ; \ delete return points upto the marked addr.
    : -NOCUT \ remove the mark, but not the return points
    R>
    L> RP@ - >R \ keep the mark as a relative address
    BACK R> RP@ + >L TRACKING \ restore it when backtracking
    >R ;

    Hans Bezemer



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Sun Mar 23 16:47:09 2025
    From Newsgroup: comp.lang.forth

    dxf <dxforth@gmail.com> wrote:

    Does anyone have a reference/details for this anywhere as I can't seem to find anything?

    Sufficient BACK TRACKING code can be found in the following document;
    I don't have a link and I won't post the code because of copyright
    mark. The discussion is in Russian but the code summary is (simple) Forth.
    The paper is about abstract iterator:
    AMONG <??????> EACH <????????> ITERATE
    but BACK TRACKING is part of the implementation and its code is shown in summary.
    The Cyrillic here is KOI8-R


    ?????????? ???????????? ???????? ? ??????? (???????????)
    ?.?.?????????

    ?????-????????????? ???????? ??????????? ? ????????????? ???
    199178, ?????-?????????, 14-? ????? ?.?., ?.39
    ?-mail: mlg@iias.spb.su

    ... Skip abstract in Russian ...

    Enhancing the capabilities of backtracking
    M.L.Gassanenko

    Abstract:
    The technique of backtracking enables one to create abstract iterator
    modules, which are very convenient, but there's a severe restriction on
    the use of backtracking in the body of loops controlled by these
    iterators. This paper introduces a loop-like control structure that
    eliminates these restrictions. A backtrackable procedure is used in it
    as an iterator that controls repeating execution of a backtrackable
    body; control is transferred to the iterator when the loop body succeeds
    (and not when it fails). Compatibility with cut statements and
    employment in rapid prototyping are discussed. A Forth implementation is presented.
    --
    me
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Sun Mar 23 23:34:55 2025
    From Newsgroup: comp.lang.forth

    Hans Bezemer <the.beez.speaks@gmail.com> wrote:

    But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT:
    and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th

    Yes, the L-stack is just a stack and what I use; however, in later evolution the L-stack became a virtual stack, a variable used in conjunction with
    the return stack. I never implemented it, the simple stack was good
    enough for me.
    --
    me
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From sjack@sjack@dontemail.me (sjack) to comp.lang.forth on Sun Mar 23 23:44:23 2025
    From Newsgroup: comp.lang.forth

    sjack <sjack@dontemail.me> wrote:


    ?????????? ???????????? ???????? ? ??????? (???????????)
    ?.?.?????????

    ?????-????????????? ???????? ??????????? ? ????????????? ???
    199178, ?????-?????????, 14-? ????? ?.?., ?.39
    ?-mail: mlg@iias.spb.su



    (Wondered how that would turn out. OK, below is UTF8

    ???????????????????? ???????????????????????? ???????????????? ?? ?????????????? (??????????????????????)
    ??.??.??????????????????

    ??????????-?????????????????????????? ???????????????? ?????????????????????? ?? ?????????????????????????? ??????
    199178, ??????????-??????????????????, 14-?? ?????????? ??.??., ??.39
    ??-mail: mlg@iias.spb.su
    --
    me
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Mar 24 12:50:58 2025
    From Newsgroup: comp.lang.forth

    On 23/03/2025 10:25 pm, Hans Bezemer wrote:
    On 23-03-2025 04:03, dxf wrote:
    On 23/03/2025 2:51 am, sjack wrote:
    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .

    Does anyone have a reference/details for this anywhere as I can't seem to
    find anything?

    A possibly useful hit but the doc is locked away:

    https://doi.org/10.1145/165628.165637

    Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt

    But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT: and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th

    It's code for a light weight stack. BTW, TRACKING is missing as well. It might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th

    : CUT:      \ mark the beginning of the fragment to cut
        R>  RP@ >L                   \ copy r-stack top addr. to L-stack
            BACK LDROP TRACKING      \ delete this mark when backtracking
        >R ;
    : -CUT  R> L> RP! >R ;  \ delete return points upto the marked addr.
    : -NOCUT    \ remove the mark, but not the return points
        R>
          L> RP@ - >R                \ keep the mark as a relative address
          BACK R> RP@ + >L  TRACKING \ restore it when backtracking
        >R ;

    Thank you (and sjack) for chasing down this one. More detail appears to be available in the SP-Forth sources directory: \devel\~profit\lib\bac4th.f

    A CP1251 to Unicode converter is here:
    https://convertcyrillic.com/#/convert

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Mar 24 13:52:10 2025
    From Newsgroup: comp.lang.forth

    On 24/03/2025 12:50 pm, dxf wrote:
    On 23/03/2025 10:25 pm, Hans Bezemer wrote:
    On 23-03-2025 04:03, dxf wrote:
    On 23/03/2025 2:51 am, sjack wrote:
    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .

    Does anyone have a reference/details for this anywhere as I can't seem to >>> find anything?

    A possibly useful hit but the doc is locked away:

    https://doi.org/10.1145/165628.165637

    Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt

    But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT: and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th

    It's code for a light weight stack. BTW, TRACKING is missing as well. It might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th

    : CUT:      \ mark the beginning of the fragment to cut
        R>  RP@ >L                   \ copy r-stack top addr. to L-stack
            BACK LDROP TRACKING      \ delete this mark when backtracking
        >R ;
    : -CUT  R> L> RP! >R ;  \ delete return points upto the marked addr.
    : -NOCUT    \ remove the mark, but not the return points
        R>
          L> RP@ - >R                \ keep the mark as a relative address
          BACK R> RP@ + >L  TRACKING \ restore it when backtracking
        >R ;

    Thank you (and sjack) for chasing down this one. More detail appears to be available in the SP-Forth sources directory: \devel\~profit\lib\bac4th.f

    A CP1251 to Unicode converter is here:
    https://convertcyrillic.com/#/convert

    M. Gassanenko's original doc with code is in directory: \devel\~mlg

    Don't know whether I should be surprised or not but after passing through Google Translate the result is amazingly good English.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Mar 24 11:15:43 2025
    From Newsgroup: comp.lang.forth

    On 24-03-2025 02:50, dxf wrote:
    On 23/03/2025 10:25 pm, Hans Bezemer wrote:
    On 23-03-2025 04:03, dxf wrote:
    On 23/03/2025 2:51 am, sjack wrote:
    Ruvim <ruvim.pinka@gmail.com> wrote:

    An artificial example:

    While wondering down roads less taken, I took a path where
    bacForth CUT: and -CUT were used in lieu of CATCH THROW .

    Does anyone have a reference/details for this anywhere as I can't seem to >>> find anything?

    A possibly useful hit but the doc is locked away:

    https://doi.org/10.1145/165628.165637

    Found it! Try this one: https://www.complang.tuwien.ac.at/anton/euroforth/ef96/gassanenko96b.txt

    But I'm gonna spoil it for you: BacForth has an extra "L" stack. CUT: and -CUT use it. You might wanna use this one if you REALLY want it: https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/stack.4th

    It's code for a light weight stack. BTW, TRACKING is missing as well. It might have to do with this one? https://sourceforge.net/p/forth-4th/code/HEAD/tree/trunk/4th.src/lib/backtrak.4th

    : CUT:      \ mark the beginning of the fragment to cut
        R>  RP@ >L                   \ copy r-stack top addr. to L-stack
            BACK LDROP TRACKING      \ delete this mark when backtracking
        >R ;
    : -CUT  R> L> RP! >R ;  \ delete return points upto the marked addr.
    : -NOCUT    \ remove the mark, but not the return points
        R>
          L> RP@ - >R                \ keep the mark as a relative address
          BACK R> RP@ + >L  TRACKING \ restore it when backtracking
        >R ;

    Thank you (and sjack) for chasing down this one. More detail appears to be available in the SP-Forth sources directory: \devel\~profit\lib\bac4th.f

    A CP1251 to Unicode converter is here:
    https://convertcyrillic.com/#/convert


    Interesting stuff. There were two things that stood out for me:
    1.
    : ENTER ( xt -- ) POSTPONE EXECUTE ; IMMEDIATE
    : ENTER >R ;

    Comment - "This (EXECUTE) is the same, but somewhat faster?"

    Interesting, because in 4tH this is still the default replacement, but I
    was told in no uncertain terms that the first and the second were wildly different. Well, according to Gassanenko it isn't too wild of an idea.. ;-)

    2.
    Gassanenko comments: BACK..TRACKING is analog to (: ;) - unfortunately I
    have forgotten what that is - I know of {: ;} and [: ;] but this one is
    new to me. Any clarification would be welcome.

    Hans Bezemer
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From dxf@dxforth@gmail.com to comp.lang.forth on Mon Mar 24 23:23:32 2025
    From Newsgroup: comp.lang.forth

    On 24/03/2025 1:52 pm, dxf wrote:
    ...
    M. Gassanenko's original doc with code is in directory: \devel\~mlg

    Don't know whether I should be surprised or not but after passing through Google Translate the result is amazingly good English.

    For anyone interested I've uploaded the translation to my google drive as:

    Backtracking.htm

    https://drive.google.com/drive/folders/1kh2WcPUc3hQpLcz7TQ-YQiowrozvxfGw


    Unlike "gassanenko96b.txt" (earlier version in English?) the translation
    has the source code.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.forth on Mon Mar 24 19:18:04 2025
    From Newsgroup: comp.lang.forth

    On 24-03-2025 13:23, dxf wrote:
    On 24/03/2025 1:52 pm, dxf wrote:
    ...
    M. Gassanenko's original doc with code is in directory: \devel\~mlg

    Don't know whether I should be surprised or not but after passing through
    Google Translate the result is amazingly good English.

    For anyone interested I've uploaded the translation to my google drive as:

    Backtracking.htm

    https://drive.google.com/drive/folders/1kh2WcPUc3hQpLcz7TQ-YQiowrozvxfGw


    Unlike "gassanenko96b.txt" (earlier version in English?) the translation
    has the source code.

    It's an interesting read - however, concerning the original CUT words -
    4tH doesn't allow direct access to the stack pointers. You may look, but
    you may not touch. Only THROW / CATCH may manipulate those pointers.

    So for me - interesting ideas, interesting read - but outside my reach.
    Still, I don't regret anything - those were the design objectives and
    they worked pretty well the last 30 years.

    Hans Bezemer

    --- Synchronet 3.20c-Linux NewsLink 1.2