Sysop: | Amessyroom |
---|---|
Location: | Fayetteville, NC |
Users: | 28 |
Nodes: | 6 (0 / 6) |
Uptime: | 50:13:50 |
Calls: | 422 |
Files: | 1,024 |
Messages: | 90,495 |
albert@spenarnc.xs4all.nl writes:Yeah right.
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.
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?
... 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?)
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.
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 ;
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.
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
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
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.
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.
: foo
<: bar ." xyz" ;>
bar
;
I find this quite handy, since upvalues (locals within foo's
context) are accessible from within bar.
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
and access to external
locals not necessary.
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 ?
On 31-01-2025 13:45, ahmed wrote:
Hi,You're welcome.
Thanks for this video and this implementation of locals.
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
On 31-01-2025 13:45, ahmed wrote:..
Hi,You're welcome.
Thanks for this video and this implementation of locals.
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
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
;
Hans Bezemer
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.
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
: 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
;
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 ;
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 { } .
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 ;
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
On Thu, 6 Feb 2025 12:57:12 +0000, Anton Ertl wrote:You mean
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.
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? ;-)
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.
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
;
However because local names are not compiled into dictionary data
space, but use their own transient dictionary entries, which
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 .
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)
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?
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)
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 )
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.
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.
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
I would be interested to see a remotely plausible example of this.
Mixing recursion and exception is ill advised by iq<160.
It may not be obvious, but
closures are sort of the same thing as OOP, just viewed from a different >angle.
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).
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
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
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.
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.
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
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
- anton
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?
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>:
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.
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
----
Ruvim
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--
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.
ALLOC moves a word to the heap freeing the a freshly generated objectthat runs from ( addr --) to HERE. This doesn't switch DP, and assumes relocatable code.
ALLOC \ move to heapWORDS \ to show that test has vanished
But, as mentioned below, the textbook examples of changing data in
closures or DOES> words are rarely found in practice.
- anton--
You can just FORGET the word.
: x ( -- xt )
here 0 , [{: addr :}d addr @ 1+ dup addr ! ;] ;
: x ( -- xt )
0 <{: w^ n :}d n ;> drop [{: n :}d n @ 1+ dup n ! ;] ;
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.
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.
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.
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
An artificial example:
Does anyone have a reference/details for this anywhere as I can't seem to find anything?
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