minforth@gmx.net (minforth) writes:
On Thu, 25 Jul 2024 12:08:58 +0000, Anton Ertl wrote:
I am thinking on a much smaller scale i.e. unification of
operators for xVALUEs and xLOCALs. ANS Forth already has
overloaded TO but stops there.
>
+TO is a common extension.
>
Certainly. I have some array operations in mind, but they
are not relevant here. The principle is like
>
: INIT { a }
[[: a ;]] \ read counter
[[: 1 +to a ;]] ; \ increment counter
DEFER count IS count
DEFER read IS read
5 INIT
COUNT COUNT READ -> should give 7
My guess is that three lines here should be
DEFER count
DEFER read
5 INIT IS count IS read
[[: ;]] define closures, but unlike gforth's more flexible
flat closures, they capture simply all upvalues (here local a).
Gforth's flag closures can be considered lower-level (they come out of
implementation ideas in the Scheme community) and are easier to
implement, but emulating closures that capture outer locals is more
cumbersome. One other aspect is that in Gforth's closures the
programmer decides whether closures are allocated in the dictionary,
on the locals stack, on the heap, or elsewhere. In the present case
the dictionary seems to be a good place, and one can write this
example as:
: init ( a -- )
align here >r , \ allocate a on the heap
r@ [n:d @ ;] \ read counter
r> [n:d 1 swap +! ;] \ increment counter
;
DEFER count
DEFER read
5 INIT IS count IS read
count count read . \ prints "7 "
INIT uses pure-stack closures [n:d consumes a value (in this exampl,
the address of the cell containing A) from the stack at closure
creation time and pushes it on the stack at closure run-time. Look,
Ma, no locals:-).
However, this does not use value-flavoured stuff, because we have to
pass the address of A around, and then it's easier to use the
variable-flavoured words. However, if you prefer the value-flavoured
words, value-flavoured fields were recently added to Gforth and can be
used to do that:
begin-structure counter
value: counter-val
end-structure
: init ( a -- )
align here >r counter allot
r@ to counter-val
r@ [n:d counter-val ;]
r> [n:d 1 swap +to counter-val ;]
;
DEFER count
DEFER read
5 INIT IS count IS read
count count read . \ prints "7 "
However, you still have to deal with the address explicitly, which
becomes especially obvious in the counter closure.
This raises the question of why you want to use closures for this
task. Why not use one of the object-oriented Forth packages, some of
which support value-flavoured fields (Mini-OOF2 among them AFAIK).
The code compiles unmodified for different types of a.
Incidentally, it compiles now with +TO, but realistically you
can't declare new 'op'TOs for too many different 'op' operators.
This statement can be read in two different ways. I think there can
be too many, but Stephen Pelc may think otherwise:-).
In any case, if the reason you want value-flavoured stuff is that you
want to be able to change the types, then yes, value-flavoured fields
(in objects or plain structures) are the way to go.
One caveat that we have here is that TO (and, AFAIK in existing
implementations, +TO) have different stack effects for VALUEs,
2VALUEs, and FVALUEs, which means that you usually cannot change the
types between the types that deal with one cell on the stack (VALUE:
CVALUE: WVALUE: LVALUE: etc.) and those that take two cells or a float
value.
- anton
-- M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.htmlcomp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html New standard: https://forth-standard.org/ EuroForth 2024: https://euro.theforth.net