For comparison, below you find the old code; it uses fewer locals, and
is factored into three words, but is it better (apart from the
functionality difference)? IMO no.
On 27/10/2022 7:51 am, Anton Ertl wrote:
If factoring simplifies code and removes the need for strange Case words,
IMO that's a good thing.
: foo ( addr1 addr2 -- )
>r 0 swap 0 0 ['] noop begin { nseqlen addr d: codeblock xt: cr? }
addr r@ u>= not while
addr @ decompile-prim2 { ulen } ulen 0< if
drop 2drop 2drop
cr? addr simple-see-word
nseqlen
else
nseqlen 0= if codeblock discode 0 0 to codeblock ['] noop to cr? then
cr? addr see-word.addr type { nseqlen1 ustart uend } ulen if
ustart 4 spaces 0 .r ." ->" uend .
assert( codeblock nip 0= )
addr @ ulen to codeblock then
nseqlen nseqlen1 max 1-
then
addr cell+ codeblock ['] cr
repeat r> drop ;
: see-code-range ( addr1 addr2 -- ) \ gforth
foo codeblock discode ;
Concerning the partial replacement of locals by keeping the values on
the return stack or data stack, that also can be done more easily in a
second step. But given that we use locals here anyway, I don't find
the result in any way preferable.
On 27/10/2022 9:32 pm, Anton Ertl wrote:Hear, hear. I also don't like long definitions. They're a horror to maintain. Short words make the logic comprehensible - at every level. Both the lower level words as well as the higher level words.
There it is. I don't find locals preferable in any way. It pushes
me to find whether there's another, potentially better, solution.
I also don't like long definitions. They're a horror to maintain.
Short words make the logic comprehensible - at every level. Both the lower >level words as well as the higher level words.
Hans Bezemer <the.beez.speaks@gmail.com> writes:
I also don't like long definitions. They're a horror to maintain.
Short words make the logic comprehensible - at every level. Both the lower >> level words as well as the higher level words.
I am awaiting you posting code for this problem to support your
claims.
If one isn't happy with variables external to forth words, one
shouldn't be happy with those internal to them.
1. The externals make the code harder to understand / maintain since they persist across function calls and can be shared between functions. You can use some naming conventions to indicate that this isn't happening, but
ugh. And you still have to re-initialize the global inside the function
on every call.
2. If the function is recursive you can't use global variables. You have to set up a separate stack for them or something. Ugh.
3. The globals keep occupying storage even when the function is not running. I thought Forthers liked stack allocation so that the memory would keep getting re-used. Locals give that.
dxforth <dxf...@gmail.com> writes:
If one isn't happy with variables external to forth words, one1. The externals make the code harder to understand / maintain since they persist across function calls and can be shared between functions. You can use some naming conventions to indicate that this isn't happening, but
shouldn't be happy with those internal to them.
ugh. And you still have to re-initialize the global inside the function
on every call.
2. If the function is recursive you can't use global variables. You have to set up a separate stack for them or something. Ugh.
3. The globals keep occupying storage even when the function is not running. I thought Forthers liked stack allocation so that the memory would keep getting re-used. Locals give that.
On 28/10/2022 3:24 am, Anton Ertl wrote:
Hans Bezemer <the.bee...@gmail.com> writes:
I also don't like long definitions. They're a horror to maintain.
Short words make the logic comprehensible - at every level. Both the lower >> level words as well as the higher level words.
I am awaiting you posting code for this problem to support yourIt's not enough he doesn't use locals in his own code - he should do
claims.
your coding as well? :)
Paul Rubin schrieb am Freitag, 28. Oktober 2022 um 10:33:30 UTC+2:If you need a carload of variables, you've forgotten (or completely disregarded)
dxforth <dxf...@gmail.com> writes:
If one isn't happy with variables external to forth words, one1. The externals make the code harder to understand / maintain since they persist across function calls and can be shared between functions. You can use some naming conventions to indicate that this isn't happening, but
shouldn't be happy with those internal to them.
ugh. And you still have to re-initialize the global inside the function
on every call.
See rule number one.2. If the function is recursive you can't use global variables. You have to set up a separate stack for them or something. Ugh.
So does C. It also introduces the penalty of stack frame creation and destruction.3. The globals keep occupying storage even when the function is not running.
I thought Forthers liked stack allocation so that the memory would keep getting re-used. Locals give that.
+1 Technical aspects and personal tastes put aside, IMO the most important benefits of using locals is instantaneous readability of code.If you need locals for that, you're not doing it correctly. Short definitions allow for
The human brain is no stack machine. We think in associations IOW by tagging names to material and non-material things and concepts.We were spoiled by Fortran, which allowed us to translate mathematical formulas almost directly to working code. Blame mathematics for that notation.
Forth is a strange animal: by factoring we try to chop long algorithms into smallestIf there is excessive stack juggling, it might be because you're (a) a totally incompetent
pieces and then try to give them meaningful names to make the code understandable.
Within those pieces we allow masochistic stack juggling and some guys even claim
to be happy.
But sometimes factorization does not come easily, see Anton's example. It is good that we have the choice to use locals where they are appropriate.Nobody says it is or should be easy! It requires thought and some tinkering. If you just want to churn out code quickly, you should do Forth - but Python! However,
For quick testing and prototyping I sometimes even use extended
locals, in their form:
: TEST { a b .. | d e .. == f g .. } .. ;
So does C. It also introduces the penalty of stack frame creation and destruction.I thought Forthers liked stack allocation so that the memory would keep
getting re-used. Locals give that.
But sometimes factorization does not come easily, see Anton's
example. It is good that we have the choice to use locals where they
are appropriate.
Nobody says it is or should be easy! It requires thought and some
tinkering. If you just want to churn out code quickly, you should do
Forth - but Python!
dxforth <dxforth@gmail.com> writes:
If one isn't happy with variables external to forth words, one
shouldn't be happy with those internal to them.
1. The externals make the code harder to understand / maintain since they persist across function calls and can be shared between functions. You can use some naming conventions to indicate that this isn't happening, but
ugh. And you still have to re-initialize the global inside the function
on every call.
2. If the function is recursive you can't use global variables. You have to set up a separate stack for them or something. Ugh.
3. The globals keep occupying storage even when the function is not running. I thought Forthers liked stack allocation so that the memory would keep getting re-used. Locals give that.
...
Here is the simplest way I can see to multiply of two complex numbers (x=a+bi, y=c+di, z=x*y):
: z* { F: a F: b F: c F: d -- F: ac-bd F: ad+bc }
a c f* b d f* f- a d f* b c f* f+ ;
That example could use FVARIABLEs instead of locals but it would be a
lot messier imho. There are no FVALUEs in standard Forth iirc, so you
have to use @ everywhere, and then your auditing process has to make
sure nothing else uses those variables, including by having anything
aliased to the pointers in the variables, and so on. There is no
equivalent of the return stack to stash intermediate FP values, so stack juggling becomes harder. Maybe it is still possible, but who wants to
spend the debugging effort? I can't believe it helps readability.
I have another example that uses FP locals and is recursive, so moving
them to FVARIABLEs isn't even workable. I don't see a general approach
other than an auxiliary FP stack implement in user code. Ugh.
On Friday, October 28, 2022 at 10:11:08 AM UTC+2, dxforth wrote:
On 28/10/2022 3:24 am, Anton Ertl wrote:
Hans Bezemer <the.bee...@gmail.com> writes:It's not enough he doesn't use locals in his own code - he should do
I also don't like long definitions. They're a horror to maintain.
Short words make the logic comprehensible - at every level. Both the lower >>>> level words as well as the higher level words.
I am awaiting you posting code for this problem to support your
claims.
your coding as well? :)
ROFL! We're slowly becoming soulmates I think. I was contemplating my
answer along the same line of thought - before I read your post. ;-)
"minf...@arcor.de" <minf...@arcor.de> writes:
For quick testing and prototyping I sometimes even use extendedThat is cool, what Forth implements that? I haven't seen it before.
locals, in their form:
: TEST { a b .. | d e .. == f g .. } .. ;
Just ending the word with "f g" seems like enough though:
: swap { a b } b a ;
On Friday, October 28, 2022 at 5:36:28 PM UTC+2,minf...@arcor.de wrote:
Paul Rubin schrieb am Freitag, 28. Oktober 2022 um 10:33:30 UTC+2:If you need a carload of variables, you've forgotten (or completely disregarded)
dxforth<dxf...@gmail.com> writes:
If one isn't happy with variables external to forth words, one1. The externals make the code harder to understand / maintain since they >>> persist across function calls and can be shared between functions. You can >>> use some naming conventions to indicate that this isn't happening, but
shouldn't be happy with those internal to them.
ugh. And you still have to re-initialize the global inside the function
on every call.
the first rule of "Thinking Forth", which is "STAMP OUT THE VARIABLES"!
Seems a bit of a dog's breakfast to me: unnecesssary use of a variable, lengthy definition and unnecessary call to PLACE, crashes if i=0,
incorrect & misleading stack comment. Compare with:
: concat ( ca1 u1 .. can un n ca -- ca+1 u )
0 over c! swap
[: ?dup if 2swap 2>r 1- recurse dup 2r> rot +place then ;]
execute count
;
incorrect & misleading stack comment.I now see where your comment about "misleading stack comment" comes
Well, the only lesson one could take from it is "there is always someone more cleverIf you need a carload of variables, you've forgotten (or completely disregarded)
the first rule of "Thinking Forth", which is "STAMP OUT THE VARIABLES"!
You don't seem to practice what you preach e.g.
On Friday, October 28, 2022 at 10:11:08 AM UTC+2, dxforth wrote:
On 28/10/2022 3:24 am, Anton Ertl wrote:
Hans Bezemer <the.bee...@gmail.com> writes:It's not enough he doesn't use locals in his own code - he should do
I also don't like long definitions. They're a horror to maintain.
Short words make the logic comprehensible - at every level. Both the lower
level words as well as the higher level words.
I am awaiting you posting code for this problem to support your
claims.
your coding as well? :)
ROFL! We're slowly becoming soulmates I think. I was contemplating my
answer along the same line of thought - before I read your post. ;-)
FORTH> : concats ( ca1 u1 .. can un n -- ca u ) 1- 0 max 0 ?DO $+ LOOP ; FORTH> S" Hello" S" , " S" world" S" !" 4 concats
[2]FORTH> type Hello, world! ok
I did do my own coding.What can I say. It shows. LOL!
Apparently there is no substance to your words. As for beingC'mon. Do you know how old I am? Do you really expect me to dance to
soulmates, dxforth has posted code to demonstrate a part of his
positions (and his code actually inspired me to transform the control structure in the way he suggested).
How many times will you code Z* ? FWIW FSLIB already has it.
FP locals isn't supported by any standard.
Some folks have suggested there should be a F>R R>F which would allow recursive f/p variables.
IIRC Wil Baden had a scheme that used memory at HERE as f/p locals.
The situations you present as requiring locals are obscure enough that
there is almost always another way. But you have to want to find it.
In Forth, locals are all about style... Unfortunately Forth was never designed for it. Compared to data stack, the return stack is the
smaller - intended only to hold return addresses and the occasional
temp. Nested definitions using locals will quickly eat it up.
dxforth <dxforth@gmail.com> writes:
How many times will you code Z* ? FWIW FSLIB already has it.
Z* is a simple example. The issue comes up with some regularity.
FP locals isn't supported by any standard.
Hmm, I didn't realize that, I mostly use gforth. It is unfortunate.
Unfortunate has been the mixed messaging. Moore couldn't be more explicit locals had no place in Forth.
dxforth <dxforth@gmail.com> writes:
Unfortunate has been the mixed messaging. Moore couldn't be more explicit >> locals had no place in Forth.
Moore, I've heard of that guy. Isn't he the one who invented PICK and
ROLL because his Forth didn't have locals? Once you've turned the stack
into an indexible array, you might as well be able to give names to the slots.
http://www.ultratechnology.com/1xforth.htmSomebody should restore these tapes. My hunch is that there will
be surprising nuance.
"The words that manipulate that stack are DUP, DROP and OVER period. There's no ..., well SWAP is very convenient and you want it, but it isn't a machine instruction. But no PICK no ROLL, none of the complex operators to let you index down into the stack."
"It is necessary to have variables."
http://www.ultratechnology.com/1xforth.htm
Marcel Hendrix <mhx@iae.nl> writes:
http://www.ultratechnology.com/1xforth.htmSomebody should restore these tapes. My hunch is that there will
be surprising nuance.
I'm sure I watched that video on youtube years ago. It looks like it
has been re-uploaded more recently, by Gavino, a surprising and nice contribution.
https://www.youtube.com/watch?v=pSnNy7IpVMg
https://youtu.be/ZYlOV7K-xOU?t=49
http://www.ultratechnology.com/1xforth.htm
dxforth <dxf...@gmail.com> writes:Well, in his 1993 interview he was quoted to have said: "But no PICK no
Moore, I've heard of that guy. Isn't he the one who invented PICK and
ROLL because his Forth didn't have locals? Once you've turned the stack
into an indexible array, you might as well be able to give names to the slots.
Moore, I've heard of that guy. Isn't he the one who invented PICK and
ROLL because his Forth didn't have locals? Once you've turned the stack
into an indexible array, you might as well be able to give names to the slots.
On Saturday, October 29, 2022 at 9:41:27 AM UTC+2, Gerry Jackson wrote:
[..]
Seems a bit of a dog's breakfast to me: unnecesssary use of a variable,
lengthy definition and unnecessary call to PLACE, crashes if i=0,
incorrect & misleading stack comment. Compare with:
: concat ( ca1 u1 .. can un n ca -- ca+1 u )
0 over c! swap
[: ?dup if 2swap 2>r 1- recurse dup 2r> rot +place then ;]
execute count
;
FORTH> : concats ( ca1 u1 .. can un n -- ca u ) 1- 0 max 0 ?DO $+ LOOP ; FORTH> S" Hello" S" , " S" world" S" !" 4 concats
[2]FORTH> type Hello, world! ok
On 29/10/2022 7:05 pm, Marcel Hendrix wrote:
FORTH> : concats ( ca1 u1 .. can un n -- ca u ) 1- 0 max 0 ?DO $+
LOOP ;
FORTH> S" Hello" S" , " S" world" S" !" 4 concats
[2]FORTH> type Hello, world! ok
: concats <# 0 ?do holds loop 0 0 #> ;
s" Hello" s" , " s" world" s" !" 4 concats type Hello, world! ok
On Saturday, October 29, 2022 at 9:41:27 AM UTC+2, Gerry Jackson wrote:
incorrect & misleading stack comment.I now see where your comment about "misleading stack comment" comes
from. In 4tH ASCIIZ strings are used - and a2 is actually the address that is returned.
That your code works is because the first line effectively terminates
the target string - and the abstraction of +PLACE does the heavy lifting.
But I forgive you ;-)Thank you
On Sunday, October 30, 2022 at 1:16:24 AM UTC-5, dxforth wrote:
http://www.ultratechnology.com/1xforth.htm
ColorForth and Moore's vision are intriguing; however, I'm out of time
for transforming into a "moti" and beginning new adventure. If I were younger, I would eagerly start with ColorForth and begin some endeavor of
UXN like "Past proofing".
On 29/10/2022 16:57, dxforth wrote:into using +PLACE and I didn't think beyond that.
On 29/10/2022 7:05 pm, Marcel Hendrix wrote:
FORTH> : concats ( ca1 u1 .. can un n -- ca u ) 1- 0 max 0 ?DO $+ LOOP ;
FORTH> S" Hello" S" , " S" world" S" !" 4 concats
[2]FORTH> type Hello, world! ok
: concats <# 0 ?do holds loop 0 0 #> ;
s" Hello" s" , " s" world" s" !" 4 concats type Hello, world! ok
Yes that's much simpler even with the inelegance of having to provide 2 cells on the stack for #> to drop.
Seeing that solution is ironic and humbling. I knew that <# ... #> and indeed have posted something about that on c.l.f in the past. I've no explanation about why I didn't think of that in my response to Hans Bezemer, I suppose his solution pointed me
It appears he [Moore] found them superfluous:
"The words that manipulate that stack are DUP, DROP and OVER
period. There's no ..., well SWAP is very convenient and you want it,
but it isn't a machine instruction. But no PICK no ROLL, none of the
complex operators to let you index down into the stack."
dxforth <dxforth@gmail.com> writes:
It appears he [Moore] found them superfluous:
"The words that manipulate that stack are DUP, DROP and OVER
period. There's no ..., well SWAP is very convenient and you want it,
but it isn't a machine instruction. But no PICK no ROLL, none of the
complex operators to let you index down into the stack."
PICK and ROLL have to have come from somewhere: if it wasn't Moore, then
who? And what about ROT, -ROT, >R, and R>?
I get that Moore used VARIABLEs for everything that I'd use locals for.
He also used CODE when Forth got in the way too much.
Today, the main problem facing programmers is ensuring the absence of behaviours rather than their presence. Writing code is way easier than
it used to be, because tools are better and computers are faster. But maintaining is harder since programs are bigger and have more people
hacking at them. If you use a VARIABLE to save a temporary value used
by a word, then anyone modifying that word, when they see that variable,
now has to check that no other word uses the variable and depends on it
for communication. Or worse, communicates through the memory cell
occupied by that variable but through some sneaky alias. VALUE avoids aliasing (no idea whether Moore used them), but locals make both issues
go away.
Finally, while I can't doubt Moore's genius, I've never understood the
vision that says the pure stack VM fits every programming problem.
You use locals because it's easier and more-or-less idiot-proof. Moore claims it leads to inefficiency.
if I have to use a variable as a temp, I do so sparingly - unlike
locals which are largely about 'readability' and therefore quantity.
I think you overstate such use of variables, but how are they a problem
when defined local to the routine which uses it?
Saving the world is tough - even for the newer programming systems you
talk about. For me, it's enough that I've been able to create a tool
I'm both comfortable using and is challenging at the same time.
I also don't see how to implement 2SWAP with
just DUP, DROP, OVER.
I also don't see how to implement 2SWAP with just DUP, DROP, OVER.Use the return stack as a "local variable holder"
and use ROT and SWAP.
Truthfully, I don't see much difference between conventional locals
and using the return stack for same.
dxforth <dxforth@gmail.com> writes:
if I have to use a variable as a temp, I do so sparingly - unlike
locals which are largely about 'readability' and therefore quantity.
Not sure what you mean about quantity, but I look at the gforth manual's locals version of MAX compared with a traditional one (both untested):
: max1 ( a b -- max ) 2dup > if drop else nip then ;
: max2 { a b -- max } a b > if a else b then ;
the locals version has less source code and (if compiled) maybe less
object code as well.
Similarly you recently posted elsewhere (158 source chars):
: concat ( a1 u1 ... an un n dest -- dest len )
0 0 begin 2>r over while swap 1- swap 2swap repeat
swap begin 2r> over while 2swap +string repeat 2drop ;
A locals version (untested) is 165 chars mostly due to extra whitespace
that could be squished out:
: concat2 ( a1 u1 ... an un n dest -- dest len )
{ n dest } 0 { len }
n 0 ?do
{ a u } a u dest len +string
u len + to len
loop
dest len ;
I can't begin to understand the stack juggling version so can't be sure
the two do the same thing.
I think you overstate such use of variables, but how are they a problem
when defined local to the routine which uses it?
How do you do that? Variables are always globals, I thought.
Another
issue with them that I forgot to mention is non-reentrancy. Like if you implement 2SWAP with variables and an interrupt handler uses it while
another call to 2SWAP is in progress, you get a Heisenbug. Oops.
dxforth <dxf...@gmail.com> writes:According to both Moore and Dijkstra, idiots shouldn't be programming.
Yes, idiot proofing is always a good goal when programming ;).
On Sunday, October 30, 2022 at 10:05:16 PM UTC-4, Paul Rubin wrote:Really?! Even my computer can do better!
I also don't see how to implement 2SWAP withUse the return stack as a "local variable holder"
just DUP, DROP, OVER.
and use ROT and SWAP.
: 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
r rot rot r> swap rot swap ;
dxforth <dxforth@gmail.com> writes:
It appears he [Moore] found them superfluous:
"The words that manipulate that stack are DUP, DROP and OVER
period. There's no ..., well SWAP is very convenient and you want it,
but it isn't a machine instruction. But no PICK no ROLL, none of the
complex operators to let you index down into the stack."
PICK and ROLL have to have come from somewhere: if it wasn't Moore, then
who? And what about ROT, -ROT, >R, and R>?
I get that Moore used VARIABLEs for everything that I'd use locals for.
You use locals because it's easier and more-or-less idiot-proof. Moore >claims it leads to inefficiency. Can't speak for his use but if I have
to use a variable as a temp, I do so sparingly - unlike locals which are >largely about 'readability' and therefore quantity.
Doug Hoffman <dhoffman888@gmail.com> writes:
I also don't see how to implement 2SWAP with just DUP, DROP, OVER.Use the return stack as a "local variable holder"
and use ROT and SWAP.
I'm doing by the quote from Chuck Moore about DUP, DROP, and OVER (and
maybe SWAP) being the only legit stack primitives, so no ROT. He does
use the return stack in his own code though.
Truthfully, I don't see much difference between conventional locals
and using the return stack for same.
There is no RPICK in standard Forth, so you can't get at the internal
slots. Moore even frowns on regular PICK. Also, you have to be able to
pop the locals if the word exits through an exception. (LOCAL) had to
be added to the standard to allow that, since the VM has to handle the >unwinding in that situation.
On Monday, October 31, 2022 at 3:05:16 AM UTC+1, Paul Rubin wrote:
According to both Moore and Dijkstra, idiots shouldn't be programming.
Yes, idiot proofing is always a good goal when programming ;).
In Forth, there are only 3 or so
"registers" (T, N, and R), and each is special. Why be so vehement that
a human rather than a machine should be juggling them?
: 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )Really?! Even my computer can do better!
r rot rot r> swap rot swap ;
rot >r rot r>
Doug Hoffman <dhoff...@gmail.com> writes:
I'm doing by the quote from Chuck Moore about DUP, DROP, and OVER (andI also don't see how to implement 2SWAP with just DUP, DROP, OVER.Use the return stack as a "local variable holder"
and use ROT and SWAP.
maybe SWAP) being the only legit stack primitives, so no ROT. He does
use the return stack in his own code though.
Truthfully, I don't see much difference between conventional localsThere is no RPICK in standard Forth, so you can't get at the internal
and using the return stack for same.
slots. Moore even frowns on regular PICK. Also, you have to be able to
pop the locals if the word exits through an exception. (LOCAL) had to
be added to the standard to allow that, since the VM has to handle the unwinding in that situation.
Sorry about that, I wasn't aware that 4th used zero terminated stringsYes - found out pretty quickly that abstracting STRING words worked in most situations - so I rarely have problems porting stuff with "cooked" strings. Unless someone uses COUNT as C@+ equivalent :-(
and just assumed that standard counted strings were used. So presumably
your version of COUNT does it by actually counting the characters.
It's fortuitous that a 0 byte means an empty string for both ways of representing a string.Yeah - I thought so too! I'm so used to ASCIIZ strings it didn't dawn upon me this might have been written for COUNTed strings. There I got the idea about the stack item!
On Sunday, October 30, 2022 at 10:54:29 PM UTC-4, Paul Rubin wrote:
Doug Hoffman <dhoff...@gmail.com> writes:Meh. What Moore has stated in recent decades also has little to do with standard Forth.
I'm doing by the quote from Chuck Moore about DUP, DROP, and OVER (and maybe SWAP) being the only legit stack primitives, so no ROT. He doesI also don't see how to implement 2SWAP with just DUP, DROP, OVER.Use the return stack as a "local variable holder"
and use ROT and SWAP.
use the return stack in his own code though.
Truthfully, I don't see much difference between conventional localsThere is no RPICK in standard Forth, so you can't get at the internal slots. Moore even frowns on regular PICK. Also, you have to be able to
and using the return stack for same.
pop the locals if the word exits through an exception. (LOCAL) had to
be added to the standard to allow that, since the VM has to handle the unwinding in that situation.
My point, which I should have stated explicitly, is that detractors of locals generally say that their use impedes factoring because items are
not on the data stack. But often these same people have no issue
with putting items on the return stack, which must also impede factoring
for the same reason. Though I really don't subscribe to the impede
factoring issue in either case.
Frequently-used core-type words like 2swap should not use locals.
In higher level problem specific words locals have a place in the code I write.
That was fun. What next, a debate about blocks vs text files?
Let's see how VFX64 fares:[..]
r rot rot r> swap rot swap rot >r rot r> 2swap
For comparison, lxf is analytical about the return stack and compiles[..]
them all to the same code (21 bytes, but 32-bit code rather than
64-bit code):
On Monday, October 31, 2022 at 4:40:09 AM UTC-4, the.bee...@gmail.com wrote:
: 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )Really?! Even my computer can do better!
r rot rot r> swap rot swap ;
rot >r rot r>
Thanks for pointing that out Hans.
VFX's optimizer lulled me into thinking that
what I showed was efficient. My bad!
r rot rot r> swap rot swap rot >r rot r> 2swapPUSH RBX PUSH QWORD [RBP+08] MOV RDX, RBX
r rot rot r> swap rot swap rot >r rot r> 2swapmov eax , [ebp+4h] mov eax , [ebp+4h] mov eax , [ebp+4h]
Doug Hoffman <dhoff...@gmail.com> writes:
On Monday, October 31, 2022 at 4:40:09 AM UTC-4, the.bee...@gmail.com wrote:
: 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )Really?! Even my computer can do better!
r rot rot r> swap rot swap ;
rot >r rot r>
Thanks for pointing that out Hans.Let's see how VFX64 fares:
VFX's optimizer lulled me into thinking that
what I showed was efficient. My bad!
r rot rot r> swap rot swap rot >r rot r> 2swapPUSH RBX PUSH QWORD [RBP+08] MOV RDX, RBX
POP RDX POP RDX MOV RBX, [RBP+08]
MOV RBX, [RBP+08] MOV RCX, [RBP+10] MOV [RBP+08], RDX
MOV [RBP+08], RDX MOV RAX, [RBP] MOV RDX, [RBP+10]
MOV RDX, [RBP+10] MOV [RBP], RCX MOV RCX, [RBP]
MOV RCX, [RBP] MOV [RBP+10], RAX MOV [RBP], RDX
MOV [RBP], RDX MOV [RBP+08], RBX MOV [RBP+10], RCX
MOV [RBP+10], RCX MOV RBX, RDX RET/NEXT
RET/NEXT RET/NEXT 28 Bytes
27 bytes 29 Bytes
For comparison, lxf is analytical about the return stack and compiles
them all to the same code (21 bytes, but 32-bit code rather than
64-bit code):
r rot rot r> swap rot swap rot >r rot r> 2swapmov eax , [ebp+4h] mov eax , [ebp+4h] mov eax , [ebp+4h]
mov [ebp+4h] , ebx mov [ebp+4h] , ebx mov [ebp+4h] , ebx
mov ebx , eax mov ebx , eax mov ebx , eax
mov eax , [ebp+8h] mov eax , [ebp+8h] mov eax , [ebp+8h]
mov ecx , [ebp] mov ecx , [ebp] mov ecx , [ebp]
mov [ebp+8h] , ecx mov [ebp+8h] , ecx mov [ebp+8h] , ecx
mov [ebp] , eax mov [ebp] , eax mov [ebp] , eax
ret near ret near ret near
- 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 2022: https://euro.theforth.net
Also the locals version will produce the same code!
: s2 {: a b c d -- c d a b :} c d a b ; ok
see s2
A4A5D4 409CB2 21 C80000 5 normal S2
409CB2 8B4504 mov eax , [ebp+4h]
409CB5 895D04 mov [ebp+4h] , ebx
409CB8 8BD8 mov ebx , eax
409CBA 8B4508 mov eax , [ebp+8h]
409CBD 8B4D00 mov ecx , [ebp]
409CC0 894D08 mov [ebp+8h] , ecx
409CC3 894500 mov [ebp] , eax
409CC6 C3 ret near
What Moore has stated in recent decades also has little to do with
standard Forth.
My point, which I should have stated explicitly, is that detractors of locals generally say that their use impedes factoring because items are
not on the data stack. But often these same people have no issue
with putting items on the return stack, which must also impede factoring
for the same reason.
'These same people' are judicious in their use of return stack. They don't have so many items that they need to name them, or require the system to manage it for them :)
dxforth <dxforth@gmail.com> writes:
It appears he [Moore] found them superfluous:
"The words that manipulate that stack are DUP, DROP and OVER
period. There's no ..., well SWAP is very convenient and you want it,
but it isn't a machine instruction. But no PICK no ROLL, none of the complex operators to let you index down into the stack."
PICK and ROLL have to have come from somewhere: if it wasn't Moore, then
who? And what about ROT, -ROT, >R, and R>?
I get that Moore used VARIABLEs for everything that I'd use locals for.
He also used CODE when Forth got in the way too much.
Back in the 1970s, computers were limited, programs were necessarily
small, and Moore espoused rewriting programs from the ground up instead
of maintaining them. The main problem facing programmers was how to
make their program implement behaviour X, for whatever X happened to be
that day. They'd put a lot of effort into coding and testing X, and
then they were done.
Today, the main problem facing programmers is ensuring the absence of behaviours rather than their presence. Writing code is way easier than
it used to be, because tools are better and computers are faster. But maintaining is harder since programs are bigger and have more people
hacking at them. If you use a VARIABLE to save a temporary value used
by a word, then anyone modifying that word, when they see that variable,
now has to check that no other word uses the variable and depends on it
for communication. Or worse, communicates through the memory cell
occupied by that variable but through some sneaky alias. VALUE avoids aliasing (no idea whether Moore used them), but locals make both issues
go away.
Finally, while I can't doubt Moore's genius, I've never understood the
vision that says the pure stack VM fits every programming problem.
Register allocation and spilling is one of the messier parts of
traditional compilers even when there are plenty of registers that don't
have weird special purposes. In Forth, there are only 3 or so
"registers" (T, N, and R), and each is special. Why be so vehement that
a human rather than a machine should be juggling them? I can understand
taht locals (if supported) complicate the traditional threaded Forth interpreter,
but I don't know how much Moore valued that. I know he did
like stack hardware (his many Forth chips) but that came later.
So the pure "stack plus VARIABLEs" seems "not even wrong" to me. I
don't understand the motivation behind it well enough to disagree per
se. And I've never seen an explanation that made sense. They have all seemed like grasping at straws.
On Monday, October 31, 2022 at 11:46:55 PM UTC-4, dxforth wrote:
'These same people' are judicious in their use of return stack. They don't >> have so many items that they need to name them, or require the system to
manage it for them :)
Yes. As it should be. I'm a habitual user of the return stack when it is all I need (as opposed to resorting to locals). Very handy and efficient.
I think thatsome voices here vastly overestimate extra complexity.
AFAICS at runtime it is enough to have bunch of extra primitives:
add and subtract from return stack pointer (could be single primitive)
and two primitives fpr each local, one for reading, the other for
storing. If one sticks to standard limit of 16 locals that is 33
primitives. And they are very simple, one or two machine instructions
for real work (plus whatever boilerplate is needed for dispatch).
At compile time main effort is to add new transient part to dictionary.[..]
On Tuesday, November 1, 2022 at 2:19:21 PM UTC+1, anti...@math.uni.wroc.pl wrote:
[..]
I think thatsome voices here vastly overestimate extra complexity.
AFAICS at runtime it is enough to have bunch of extra primitives:
add and subtract from return stack pointer (could be single primitive)
and two primitives fpr each local, one for reading, the other for
storing. If one sticks to standard limit of 16 locals that is 33
primitives. And they are very simple, one or two machine instructions
for real work (plus whatever boilerplate is needed for dispatch).
Aren't you forgetting what happens when you call a word that also
uses locals? What about recursion?
What happens when bot locals
and the R-stack are used?
Another problem: what to do with SEE ?
Paul Rubin <no.e...@nospam.invalid> wrote:
dxforth <dxf...@gmail.com> writes:
It appears he [Moore] found them superfluous:
"The words that manipulate that stack are DUP, DROP and OVER
period. There's no ..., well SWAP is very convenient and you want it,
but it isn't a machine instruction. But no PICK no ROLL, none of the complex operators to let you index down into the stack."
PICK and ROLL have to have come from somewhere: if it wasn't Moore, then who? And what about ROT, -ROT, >R, and R>?
I get that Moore used VARIABLEs for everything that I'd use locals for.
He also used CODE when Forth got in the way too much.
Back in the 1970s, computers were limited, programs were necessarily
small, and Moore espoused rewriting programs from the ground up instead
of maintaining them. The main problem facing programmers was how to
make their program implement behaviour X, for whatever X happened to be that day. They'd put a lot of effort into coding and testing X, and
then they were done.
Today, the main problem facing programmers is ensuring the absence of behaviours rather than their presence. Writing code is way easier than
it used to be, because tools are better and computers are faster. But maintaining is harder since programs are bigger and have more people hacking at them. If you use a VARIABLE to save a temporary value used
by a word, then anyone modifying that word, when they see that variable, now has to check that no other word uses the variable and depends on it
for communication. Or worse, communicates through the memory cell
occupied by that variable but through some sneaky alias. VALUE avoids aliasing (no idea whether Moore used them), but locals make both issues
go away.
Finally, while I can't doubt Moore's genius, I've never understood the vision that says the pure stack VM fits every programming problem.I think thatsome voices here vastly overestimate extra complexity.
Register allocation and spilling is one of the messier parts of
traditional compilers even when there are plenty of registers that don't have weird special purposes. In Forth, there are only 3 or so
"registers" (T, N, and R), and each is special. Why be so vehement that
a human rather than a machine should be juggling them? I can understand taht locals (if supported) complicate the traditional threaded Forth interpreter,
AFAICS at runtime it is enough to have bunch of extra primitives:
add and subtract from return stack pointer (could be single primitive)
and two primitives fpr each local, one for reading, the other for
storing. If one sticks to standard limit of 16 locals that is 33
primitives. And they are very simple, one or two machine instructions
for real work (plus whatever boilerplate is needed for dispatch).
At compile time main effort is to add new transient part to dictionary.
One needs to decide where to put it. With standard restriction
of local declarations fitting on single line one could use a fixed
size area of order 120-200 bytes.
I think that some voices here vastly overestimate extra complexity.I did locals in my uBASIC interpreter - because it's BASIC - a Fortran derivative - it's fitting. But it requires setting up and releasing a stack frame,
AFAICS at runtime it is enough to have bunch of extra primitives:33 primitives? And you call that "minor overhead"? My entire VM has about
add and subtract from return stack pointer (could be single primitive)
and two primitives fpr each local, one for reading, the other for
storing. If one sticks to standard limit of 16 locals that is 33
primitives. And they are very simple, one or two machine instructions
for real work (plus whatever boilerplate is needed for dispatch).
Are you saying Forth is inadequate - or that it's your choice to extend it with locals? If Forth is inadequate it would mean I've wasted 40 years onTrue. Thinking about programming in a Forth way has significantly influenced my C style. Now I need to go the opposite way: translating C to Forth, so I can have loads of local variables - and write functions (not words) of five pages without ever posing the question: "Do I really need those - or can I do something
a bum steer. Locals users too.
On Tuesday, November 1, 2022 at 3:23:07 PM UTC+1, dxforth wrote:
Are you saying Forth is inadequate - or that it's your choice to extend it with locals? If Forth is inadequate it would mean I've wasted 40 years onTrue. Thinking about programming in a Forth way has significantly influenced my
a bum steer. Locals users too.
C style. Now I need to go the opposite way: translating C to Forth, so I can have loads of local variables - and write functions (not words) of five pages without ever posing the question: "Do I really need those - or can I do something
clever to eradicate them?"
See: https://sourceforge.net/p/forth-4th/wiki/This%20is%20Forth/ and https://sourceforge.net/p/forth-4th/wiki/Understand%20your%20algorithm/
Hans Bezemer
Oh, I'm not advocating variables - locals or otherwise. What I see is a lot of promiscuous use of the former as if there were no cost. Here's an example of using extra locals - not out of necessity - but 'style':
https://gforth.org/manual/Locals-programming-style.html
If anyone is writing applications 'in Forth', it's because they've
stopped pursuing 'the vision splendid' ...
dxforth <dxforth@gmail.com> writes:
Oh, I'm not advocating variables - locals or otherwise. What I see is a lot >> of promiscuous use of the former as if there were no cost. Here's an example
of using extra locals - not out of necessity - but 'style':
https://gforth.org/manual/Locals-programming-style.html
In that example, there is some stuff in locals, but getting rid of the
locals would mean keeping the same stuff on the data stack (and maybe
partly the return stack). The total memory used is the same. In some systems the return (or locals) stack might be too small, but if you're
going to use locals (or anything else) at all, obviously you want to
size the stacks to accomodate your usage.
On Tuesday, November 1, 2022 at 2:19:21 PM UTC+1, anti...@math.uni.wroc.pl wrote:
[..]
I think thatsome voices here vastly overestimate extra complexity.
AFAICS at runtime it is enough to have bunch of extra primitives:
add and subtract from return stack pointer (could be single primitive)
and two primitives fpr each local, one for reading, the other for
storing. If one sticks to standard limit of 16 locals that is 33 primitives. And they are very simple, one or two machine instructions
for real work (plus whatever boilerplate is needed for dispatch).
Aren't you forgetting what happens when you call a word that also
uses locals? What about recursion? What happens when bot locals
and the R-stack are used?
At compile time main effort is to add new transient part to dictionary.[..]
Complexity depends on simply *implementing* locals versus *optimizing* them. The former is indeed trivially simple.
My point was it went from 4 locals to 6 for reasons of style. It may be C-style to expend resources this way (I wouldn't know)
but I doubt it's Moore's.
But what are implications of using locals in Forth? It's this: A
stack-based language that cannot exist without the help of locals has
failed and therefore does not deserve to exist.
On Tuesday, November 1, 2022 at 2:19:21 PM UTC+1, anti...@math.uni.wroc.pl wrote:
I think that some voices here vastly overestimate extra complexity.I did locals in my uBASIC interpreter - because it's BASIC - a Fortran derivative - it's fitting. But it requires setting up and releasing a stack frame,
copying values there - that's a whole lot of overhead. For some ugly C-ism. As if we didn't have enough of those in ANS Forth.
AFAICS at runtime it is enough to have bunch of extra primitives:33 primitives? And you call that "minor overhead"? My entire VM has about
add and subtract from return stack pointer (could be single primitive)
and two primitives fpr each local, one for reading, the other for
storing. If one sticks to standard limit of 16 locals that is 33 primitives. And they are very simple, one or two machine instructions
for real work (plus whatever boilerplate is needed for dispatch).
100 primitives.
dxforth <dxforth@gmail.com> writes:
My point was it went from 4 locals to 6 for reasons of style. It may be
C-style to expend resources this way (I wouldn't know)
In C these days, the extra locals wouldn't expend any resources in most cases, since the compiler would optimize them away.
But what are implications of using locals in Forth? It's this: A
stack-based language that cannot exist without the help of locals has
failed and therefore does not deserve to exist.
Well, Moore used VARIABLEs instead of locals, so the pure stack vision already failed because of that.
One could simply say Forth works better
in the presence of some impurity. Locals are another, perhaps cleaner,
way to add the impurity.
AFAIK optimizers do a better job when the code presented is already optimal.
Well, Moore used VARIABLEs instead of locals,Does he?
dxforth <dxforth@gmail.com> writes:
[...]
Well, Moore used VARIABLEs instead of locals,Does he?
I believe so. I remember looking at cmforth and some of the GA144 code
and seeing variables used that way. I also remember asking Elizabeth
about the complex multiplication example, and her replying that Moore
didn't hesitate to use CODE if it made things easier. He wasn't a
purist about staying with Forth words.
In the 1970s there just wasn't room for purity in software. Maybe APL
came closest. Lisp was born from the most purest mathematical
abstraction (lambda calculus) but its implementations were full of low
level hackery. The purest language now is Haskell but it is also full
of hacks.
One extra remark: as Anton noted instead of 32 access primitives
I could use just 2. But AFACS in threaded code each use of
Anton version would add 2 words of code (one for primitive itself,
second for parameter). And assembly code of primitive would
be a bit more complex. My version when used needs just one
word of code. And assembly should be pretty efficient, at least
as efficient as named constant or value and possibly more efficient.
Which means that when used in good way locals should lead to
smaller and more efficient code.
Maybe you are worried about used dictionary slots? AFAICS Forthers
are not shy about defining small special purpose words that
get used once or twice. Looking at extras for Mecrisp I saw
MCU definition files that define hundreds of constants, so even
for small targets people use a lot dictionary slots. So,
I call those 33 slots minor overhead.
I am not sure what is troubling you here. That they are called
"primitives"? Access primitives are very simple and very similar
to each other, conceptually there is almost no increase in complexity.
That they need to be coded in assembler? Albert's ciforth has about
300 words defiend in assembler, and from glance at his code I think
that most is longer than proposed primitives. So it seems that one
would get 5-7% increase in amount of assembler code and to that
matter simpler than much of the rest. Of course, you may that pride
that you need less assember code. However, I take pragmatic view
here: assembler is problematic because one can do tricky things
which are hard to understand. But the primitives are so simple that
there is not problem with understanding.
And you may not belive, but I have reasons to think that
using locals within Forth implementation (not for style, but
when it leads to gain!) would make code smaller, likely
compensating space taken by primitives.
On 1/11/2022 10:44 pm, Doug Hoffman wrote:
On Monday, October 31, 2022 at 11:46:55 PM UTC-4, dxforth wrote:
'These same people' are judicious in their use of return stack.
I'm a habitual user of the return stack when it is all
I need (as opposed to resorting to locals).
Are you saying ... that it's your choice to extend [Forth]
with locals?
If Forth is inadequate it would mean I've wasted 40 years on
a bum steer. Locals users too.
My interest is in discovering whether Moore's system works.
This is about as bad at it gets (decompiled, not formatted):
: FORGET-VOC 2DUP SWAP U< IF SWAP >R >WID BEGIN DUP DUP BEGIN >LFA @
DUP R@ U< UNTIL SWAP >LFA ! >LFA @ DUP 0= UNTIL DROP R> ELSE >VFA @
VOC-LINK ! ONLY FORTH DEFINITIONS THEN ;
As am I and I believe everyone else I've seen use the return stackThat's only half the story. I learned this trick from the guy who wrote the FIG editor - you don't randomly place stuff there, you place the stuff that is either
to stash data stack items.
Did I say that all colon definitions I write use locals?CONCAT didn't - I loved it. You see, you are perfectly capable to do better ;-)
and trade it for an IMHO inferior way of converting an idea into working code.
On Thursday, November 3, 2022 at 7:41:55 PM UTC+1, the.bee...@gmail.com wrote:If you're talking about a mechanical proces like code generation
[..]
and trade it for an IMHO inferior way of converting an idea into working code.It was demonstrated to you (e.g., by Peter Fälth) that it doesn't matter how you write the Forth source, it converts to the same code, given a reasonable compiler.
-marcel
So now one is dependent on "a reasonable compiler". GCC here we come.
On Thursday, November 3, 2022 at 7:41:55 PM UTC+1, the.bee...@gmail.com wrote:
[..]
and trade it for an IMHO inferior way of converting an idea into working code.
It was demonstrated to you (e.g., by Peter Fälth) that it doesn't matter
how you write the Forth source, it converts to the same code, given a reasonable compiler.
On Tuesday, November 1, 2022 at 10:23:07 AM UTC-4, dxforth wrote:
...
If Forth is inadequate it would mean I've wasted 40 years on
a bum steer. Locals users too.
I don't follow that logic. How could the way I, or anyone else,
use Forth impact whether or not you have wasted your time?
How else to describe a language that folks say they can't use unless
locals are added.
On Thursday, November 3, 2022 at 7:41:55 PM UTC+1, the.bee...@gmail.com wrote:
[..]
and trade it for an IMHO inferior way of converting an idea into working code.It was demonstrated to you (e.g., by Peter Fälth) that it doesn't matter how you write the Forth source, it converts to the same code, given a reasonable compiler.
-marcel
dxforth <dxforth@gmail.com> writes:
How else to describe a language that folks say they can't use unless
locals are added.
No software is ever finished until its last user is dead. So all
software is inadequate in one way or another. We do what we can in
order to get by anyway.
In my own Forth programming I do not use locals. I have not seen the need
for them and I do not like the way they are specified to look like a comment! In lxf I have instead another feature n LBUFFER: <name> that reserves n
byte on the return stack that can be accessed with ! @ at <name>. Just like a variable. This is useful to pass structures to systems call for example.
This is about as bad at it gets (decompiled, not formatted):
: FORGET-VOC 2DUP SWAP U< IF SWAP >R >WID BEGIN DUP DUP BEGIN >LFA @
DUP R@ U< UNTIL SWAP >LFA ! >LFA @ DUP 0= UNTIL DROP R> ELSE >VFA @
VOC-LINK ! ONLY FORTH DEFINITIONS THEN ;
I had to guess at the stack effects of the internal words and have no
idea what the parameters are supposed to mean, but this looks roughly
like:
: FORGET-VOC { a b }
b a u< IF
b >WID
BEGIN
BEGIN b >LFA @ { c } c a U< UNTIL
b >LFA !
b 0= UNTIL
b c a
ELSE
a b >VFA @
VOC-LINK ! ONLY FORTH DEFINITIONS
THEN ;
Actually that is probably wrong since there is a different amount of
stuff on the stack depending on which branch of the IF is taken.
Some comments and stack diagrams would surely help.
dxforth <dxf...@gmail.com> writes:
AFAIK optimizers do a better job when the code presented is already optimal.These days optimizers work by first splitting everything out into
separate variables so that nothing is ever updated (static single
assignment or SSA form), and then recombining the variables. I have
never implemented SSA and don't understand it perfectly, but I believe
the SSA forms of the 4-local and 6-local versions of that code would be
very similar. Anton would know this much better than I do.
Well, Moore used VARIABLEs instead of locals,Does he?
I believe so. I remember looking at cmforth and some of the GA144 code
and seeing variables used that way. I also remember asking Elizabeth
about the complex multiplication example, and her replying that Moore
didn't hesitate to use CODE if it made things easier. He wasn't a
purist about staying with Forth words.
In the 1970s there just wasn't room for purity in software. Maybe APL
came closest. Lisp was born from the most purest mathematical
abstraction (lambda calculus) but its implementations were full of low
level hackery. The purest language now is Haskell but it is also full
of hacks.
In article <87tu3gc77i.fsf@nightsong.com>,
Paul Rubin <no.email@nospam.invalid> wrote:
This is about as bad at it gets (decompiled, not formatted):
: FORGET-VOC 2DUP SWAP U< IF SWAP >R >WID BEGIN DUP DUP BEGIN >LFA @
DUP R@ U< UNTIL SWAP >LFA ! >LFA @ DUP 0= UNTIL DROP R> ELSE >VFA @
VOC-LINK ! ONLY FORTH DEFINITIONS THEN ;
I had to guess at the stack effects of the internal words and have no
idea what the parameters are supposed to mean, but this looks roughly
like:
: FORGET-VOC { a b }
b a u< IF
b >WID
BEGIN
BEGIN b >LFA @ { c } c a U< UNTIL
b >LFA !
b 0= UNTIL
b c a
ELSE
a b >VFA @
VOC-LINK ! ONLY FORTH DEFINITIONS
THEN ;
Actually that is probably wrong since there is a different amount of
stuff on the stack depending on which branch of the IF is taken.
Some comments and stack diagrams would surely help.
It was not intended to be analysed, but to show how approximately
the most complicated words look.
dxforth schrieb am Donnerstag, 3. November 2022 um 06:29:37 UTC+1:
My interest is in discovering whether Moore's system works.
Did it work for himself? I gathered that he changed it all the time.
Fig-Forth's FORGET was simple but it broke once vocabs were added.
Oh, I'd say organized Forth is absolutely dead. I agree with your
last line.
dxforth <dxforth@gmail.com> writes:
Oh, I'd say organized Forth is absolutely dead. I agree with your
last line.
Well, what was organized Forth trying to do when it was alive? Was it
trying to crank out working code by hook or by crook, or was it trying
to pursue a vision of stack combinator purity? If it was merely trying
to crank out code, I still think locals help with that, and haven't seen persuasive reasoning to the contrary.
And Moore sometimes seems to be operating
in a different world than the rest of us.
He did say he didn't create Forth for you. What you do with it is your business.
On Saturday, November 5, 2022 at 7:50:11 AM UTC+1, dxforth wrote:
[..]
He did say he didn't create Forth for you. What you do with it is your
business.
That effectively kills all discussion. What does it matter then
what he said, or what you or I say?
ISTM Paul did that when he said Moore was "operating in a different
world to the rest of us". Paul has all but said that he won't use
Forth unless he can use locals.
There's certainly no "purity" there - just the promise of supporters
for ANS if the TC acquiesced.
dxforth <dxforth@gmail.com> writes:
ISTM Paul did that when he said Moore was "operating in a different
world to the rest of us". Paul has all but said that he won't use
Forth unless he can use locals.
I haven't said that, I've said that I find locals make Forth easier for
me to use. I find Forth difficult compared with other languages even
with locals, but I use it for some things anyway because it is
interesting.
There's certainly no "purity" there - just the promise of supporters
for ANS if the TC acquiesced.
The TC was an industry group, I thought. As far as I can tell, the opposition to locals is more from an artistic perspective than an
engineering one.
I'm fine with doing stuff for artistic reasons, but I
had imagined that the TC's audience was more concerned with
practicality.
Just about every introductory text to Forth says to minimize variables
and your response is you find it too difficult.
Looks to me they [the TC] were more interested in numbers. Not that
it got them many 'happy campers' given the ensuing furore of type of
locals. Such is politics.
dxforth <dxforth@gmail.com> writes:
Just about every introductory text to Forth says to minimize variables
and your response is you find it too difficult.
If you mean VARIABLEs then of course I want to minimize those. I'm not trying to be a wise-acre but I have thought of VARIABLEs and locals as distinct things.
Looks to me they [the TC] were more interested in numbers. Not that
it got them many 'happy campers' given the ensuing furore of type of
locals. Such is politics.
I don't see the downside. The compromise basically was to add (LOCAL)
to implementations that didn't already have it. That's a new primitive,
but the other stuff can be done in terms of it using Forth words. I
hope that implementing (LOCAL) didn't cause anyone too much pain. Once
it was there, nobody was required to use it, but it was available for
those who wanted it.
On 6/11/2022 5:08 pm, Paul Rubin wrote:
dxforth <dxf...@gmail.com> writes:Yes - for those who hadn't grasped the difference between Forth and other languages. I'll admit it - I was one of them. The mere inclusion of locals
in ANS-Forth had me fooled. For quite a long time I thought locals were
a part of Forth - until a chance reading of a post by Jeff Fox.
On Sunday, November 6, 2022 at 9:47:16 AM UTC+1, dxforth wrote:
On 6/11/2022 5:08 pm, Paul Rubin wrote:
dxforth <dxf...@gmail.com> writes:Yes - for those who hadn't grasped the difference between Forth and other
languages. I'll admit it - I was one of them. The mere inclusion of locals >> in ANS-Forth had me fooled. For quite a long time I thought locals were
a part of Forth - until a chance reading of a post by Jeff Fox.
Did any of Jeff's Forth code get archived somewhere? I never was able
to find anything he actually wrote himself.
On Sunday, November 6, 2022 at 9:47:16 AM UTC+1, dxforth wrote:
On 6/11/2022 5:08 pm, Paul Rubin wrote:
dxforth <dxf...@gmail.com> writes:Yes - for those who hadn't grasped the difference between Forth and other
languages. I'll admit it - I was one of them. The mere inclusion of locals >> in ANS-Forth had me fooled. For quite a long time I thought locals were
a part of Forth - until a chance reading of a post by Jeff Fox.
Did any of Jeff's Forth code get archived somewhere? I never was able
to find anything he actually wrote himself.
For quite a long time I thought locals were a part of Forth - until a
chance reading of a post by Jeff Fox.
dxforth <dxf...@gmail.com> writes:
For quite a long time I thought locals were a part of Forth - until a chance reading of a post by Jeff Fox.It might have been this (3 parts): http://www.ultratechnology.com/forth.htm ...
There's lots more, I've only scratched the surface. So I don't
understand why it is that locals in particular draw ire while everything
else skates by.
It might have been this (3 parts): http://www.ultratechnology.com/forth.htm ...
Among other ideas in the article:
- Optimizing compilers are too complicated. It's better for your
compiler/interpreter to make slow code just to make the implementation
simpler, because you if your applications are minimalistic enough,
they will run fast anyway.
lits thenpeephole-compile, ;
- Blocks instead of files. I thought this one had resolved some decades ago.
- Tail recursion instead of loops. Ok, Haskellers like this too. But I
thought someone was complaining about it here on clf just recently.
- Eliminate SMUDGE so any reference to an existing word becomes a recursive
call. If you want to redefine the word, think of a new name for it.
(I'm not sure I understand this bit--it's in the part about cmForth).
- Late binding is slow, based on implementating with S" DUP" EVALUATE
I mean who does that?
Late binding to most of us basically means DEFER.
- Say X X X X X instead of using a loop. CASE is an abomination. Do
lots of your application at compile time instead of run time, to keep
stuff out of the final executable. I thought most compilers did that
Connect your
computer to the internet? A 1K TCP stack might be sort of possible, but
TLS is probably not doable in that.
There's lots more, I've only scratched the surface. So I don't
understand why it is that locals in particular draw ire while everything
else skates by.
That's an interesting question. Why did Andrew Haley disparage
recognizers that require relatively little code, while accepting
without comment the SUBSTITUTE proposal that requires much more code.
I think I asked him that, and his answer was along the lines that the
text interpreter (for which the recognizer proposal would standardize
a part) is a fundamental part of Forth, while SUBSTITUTE is
peripheral. Maybe the reason is similar for stack vs. locals.
- anton
dxforth <dxforth@gmail.com> writes:
For quite a long time I thought locals were a part of Forth - until a
chance reading of a post by Jeff Fox.
It might have been this (3 parts): http://www.ultratechnology.com/forth.htm
A very interesting article. I read it some years ago (it's one of the
things that got/kept me interested in Forth) and I just re-read it. It >contains wisdom that can be learned from but that I think shouldn't be
taken too literally.
Among other ideas in the article:
- Optimizing compilers are too complicated. It's better for your
compiler/interpreter to make slow code just to make the implementation
simpler, because you if your applications are minimalistic enough,
they will run fast anyway.
- Blocks instead of files. I thought this one had resolved some decades ago.
- No floating point arithmetic. Used scaled integers instead, and
concoct your own measurement units in your app to make the scaled
I originally chose mV for internal units. But using 6400 mV = 4096
units replaces a divide with a shift and requires only 2 multiplies
per transistor.
- Tail recursion instead of loops. Ok, Haskellers like this too. But I
thought someone was complaining about it here on clf just recently.
- "Face the problem, think about it until you can picture the solution
as about 1K of code or less. Until then you don't really understand it."
- Eliminate SMUDGE so any reference to an existing word becomes a recursive
call. If you want to redefine the word, think of a new name for it.
(I'm not sure I understand this bit--it's in the part about cmForth).
- Late binding is slow, based on implementating with S" DUP" EVALUATE
I mean who does that? Late binding to most of us basically means DEFER.
- Say X X X X X instead of using a loop. CASE is an abomination. Do
lots of your application at compile time instead of run time, to keep
stuff out of the final executable. I thought most compilers did that
- "Removing wordlists is also one of the techniques that greatlyIn the Gbyte area I am a proponent of wordlists. It is not
simplified other words in the system and allowed Chuck to build a 1K
sized Forth that can compile applications in a click."
- replace ! and @ with A! and A@, having an A register in the virtual
machine that also has an autoincrement mode
Some of this stuff is hardware oriented, some makes sense, and some just >makes me smile. Got a distributed company and want to run your own
payroll? Your software will have to deal with the tax codes of 100s of >overlapping jurisdictions. Good luck fitting that in 1K of code.
Software defined radio, video codec, etc.? Same thing. Connect your >computer to the internet? A 1K TCP stack might be sort of possible, but
TLS is probably not doable in that. Want it to have wifi or bluetooth?
Don't get me started.
The article has no mention of multitasking (Forth's traditional
cooperative multitasker is breathtakingly simple and is another thing
that impressed me about Forth). I had thought Polyforth was done by
Chuck but maybe I'm wrong.
There's lots more, I've only scratched the surface. So I don't
understand why it is that locals in particular draw ire while everything
else skates by.
Somewhere in the talk of using factoring instead of locals, the need to
name the factors seems to have forgotten. If avoiding thinking up names
for the locals speaks in favor of stack juggling, the similar need to
name small factors shouldn't be ignored. (I usually name factors FOO.1, >FOO.2 etc. though).
Paul Rubin schrieb am Montag, 7. November 2022 um 05:41:54 UTC+1:
dxforth <dxf...@gmail.com> writes:People love hot topics, particularly the heaters love them. Yet it is only old stuff warmed up. Couple of years ago it had been OOP etc.
For quite a long time I thought locals were a part of Forth - until a chance reading of a post by Jeff Fox.It might have been this (3 parts): http://www.ultratechnology.com/forth.htm ...
There's lots more, I've only scratched the surface. So I don't
understand why it is that locals in particular draw ire while everything else skates by.
Those recommendations by Fox/Moore read like coming from a
(macro) assembler perspective. No surprise there. Forth can be a powerful macro assembler.
But when you have to handle fat data objects in your embedded systems
you need more adequate tooling. Since Forth can be extended easily,
why not tool up Forth with what is needed.
AFAIU exactly THIS was Moore's philosophy. I guess he would have laughed
at "language purity" arguments.
There may also be the usual elitism at work. Some programmers brought
up the hard way think of themselves as elite because of that, and
resent locals which, if accepted, make all their elite competences
appear worthless.
On Monday, November 7, 2022 at 9:25:46 AM UTC+1, minf...@arcor.de wrote:
Paul Rubin schrieb am Montag, 7. November 2022 um 05:41:54 UTC+1:
dxforth <dxf...@gmail.com> writes:People love hot topics, particularly the heaters love them. Yet it is only old stuff warmed up. Couple of years ago it had been OOP etc.
For quite a long time I thought locals were a part of Forth - until a chance reading of a post by Jeff Fox.It might have been this (3 parts): http://www.ultratechnology.com/forth.htm
...
There's lots more, I've only scratched the surface. So I don't
understand why it is that locals in particular draw ire while everything else skates by.
Those recommendations by Fox/Moore read like coming from a
(macro) assembler perspective. No surprise there. Forth can be a powerful macro assembler.
But when you have to handle fat data objects in your embedded systems
you need more adequate tooling. Since Forth can be extended easily,
why not tool up Forth with what is needed.
AFAIU exactly THIS was Moore's philosophy. I guess he would have laughedForth has many faces, maybe as many faces as it has users.
at "language purity" arguments.
Given a sufficiently powerful system, a domain expert can, and will, extend it
in a fashion that quickly becomes completely incomprehensible to other Forth users. CM is a prime example of that. Unfortunately, it does not scale.
Forth has many faces, maybe as many faces as it has users.
Given a sufficiently powerful system, a domain expert can, and will, extend it
in a fashion that quickly becomes completely incomprehensible to other Forth users. CM is a prime example of that. Unfortunately, it does not scale.
On 7/11/2022 3:41 pm, Paul Rubin wrote:
dxforth <dxf...@gmail.com> writes:
For quite a long time I thought locals were a part of Forth - until a
chance reading of a post by Jeff Fox.
It might have been this (3 parts): http://www.ultratechnology.com/forth.htm
A very interesting article. I read it some years ago (it's one of the things that got/kept me interested in Forth) and I just re-read it. It contains wisdom that can be learned from but that I think shouldn't be taken too literally.Jeff could be a bit like Hugh but his point that I related about locals in Forth not serving the same function as locals in C is indisputable.
dxforth <dxforth@gmail.com> writes:
For quite a long time I thought locals were a part of Forth - until a
chance reading of a post by Jeff Fox.
It might have been this (3 parts): http://www.ultratechnology.com/forth.htm
A very interesting article. I read it some years ago (it's one of the
things that got/kept me interested in Forth) and I just re-read it. It contains wisdom that can be learned from but that I think shouldn't be
taken too literally.
Jeff could be a bit like Hugh but his point that I related about locals in Forth not serving the same function as locals in C is indisputable.True. You could let data flow over a stack in C (with a little trouble). However, it's alien to the very concept of C, which uses stack frames
However, it's alien to the very concept of C, which uses stack frames
as its primary data flow mechanism.
Given a sufficiently powerful system, a domain expert can, and will, extend it >in a fashion that quickly becomes completely incomprehensible to other Forth >users. CM is a prime example of that. Unfortunately, it does not scale.
Modern 64-bit C passes most arguments through CPU registers.
Times are a-changing ...
Chuck Moore's work on Forth is an example that is not only
comprehensible to others, but has inspired many others to use it,
adapt it to their needs, extend it, and do their own things with it.
And it scaled quite well. Thousands of people have used Forth.
It helps to keep both the implementation and the interface simple, it
does not help to keep the implementation simple at the cost of
interface complexity.
I wonder if Forth performance could be improved by keeping a larger
stack segment in CPU registers, than by meanwhile classic
TOS-only-caching.
AFAIU the bottleneck is bringing the stack to its canonical state, but
this could be reduced by keeping some registers in reserve (top stack
segment "floating" in CPU registers).
In the end, passing top stack segments already through registers would
about eliminate the difference to using locals.
"minf...@arcor.de" <minf...@arcor.de> writes:
Modern 64-bit C passes most arguments through CPU registers.C calling conventions on 32-bit architectures such as ARM (1985), MIPS (1986), SPARC (1986) etc. all pass parameters through registers.
Times are a-changing ...
Given the age and current status of these architectures, I hesitate to
call them modern.
the.bee...@gmail.com schrieb am Montag, 7. November 2022 um 17:01:21 UTC+1:
However, it's alien to the very concept of C, which uses stack frames
as its primary data flow mechanism.
Modern 64-bit C passes most arguments through CPU registers.
Times are a-changing ...
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
Chuck Moore's work on Forth is an example that is not only
comprehensible to others, but has inspired many others to use it,
adapt it to their needs, extend it, and do their own things with it.
And it scaled quite well. Thousands of people have used Forth.
Forth itself is useful and inspiring, but when I look at actual Forth
code written by Chuck Moore, maybe it's just me, but I have found it
quite incomprehensible. That basically means cmForth and some of his
GA144 code, so far.
I don't know what else is out there.
Marcel Hendrix <m...@iae.nl> writes:[..]
Chuck Moore's work on Forth is an example that is not
only comprehensible to others, but has inspired many others to use it,
adapt it to their needs, extend it, and do their own things with it.
And it scaled quite well. Thousands of people have used Forth.
There's plenty of forth code about which demonstrates locals are
rarely, if ever, needed
"Don't use local variables. Don't come up with new syntaxs for
describing them and new schemes for implementing them. You can make
local variables very efficient especially if you have local registers
to store them in, but don't. It's bad. It's wrong." - C.M.
dxforth <dxforth@gmail.com> writes:
There's plenty of forth code about which demonstrates locals are
rarely, if ever, needed
Yes, that code shows that stuff can usually or always be done without
locals. I don't doubt that. What I don't understand is what makes a without-locals version superior to a locals version.
"minf...@arcor.de" <minf...@arcor.de> writes:
I wonder if Forth performance could be improved by keeping a largerTOS+NOS is also a thing. Mecrisp keeps more stack slots in registers
stack segment in CPU registers, than by meanwhile classic
TOS-only-caching.
but has an actual register allocator, so maybe you meant something
simpler.
AFAIU the bottleneck is bringing the stack to its canonical state, butMecrisp has some code for tidying the stack like that, but I thought it
this could be reduced by keeping some registers in reserve (top stack segment "floating" in CPU registers).
was because the word being compiled didn't know where it was being
called from, so it had to present a consistent stack picture wherever
the caller was.
I wonder if Forth performance could be improved by keeping a larger stack >segment in CPU registers, than by meanwhile classic TOS-only-caching.
AFAIU the bottleneck is bringing the stack to its canonical state, but this >could be reduced by keeping some registers in reserve (top stack segment >"floating" in CPU registers).
In the end, passing top stack segments already through registers would
about eliminate the difference to using locals.
Given a compiler that is analytical about stack items of all stacks
and about locals, and works at the colon definition level (rather than
the basic block level), I expect essentially the same code from
keeping data on the stack or keeping it in locals: they all are mapped
to registers. Now I only have to write such a compiler:-).
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
Chuck Moore's work on Forth is an example that is not only
comprehensible to others, but has inspired many others to use it,
adapt it to their needs, extend it, and do their own things with it.
And it scaled quite well. Thousands of people have used Forth.
Forth itself is useful and inspiring, but when I look at actual Forth
code written by Chuck Moore, maybe it's just me, but I have found it
quite incomprehensible. That basically means cmForth and some of his
GA144 code, so far.
The Jeff Fox article calls rather for keeping the implementation simple
at all costs. For example, having OKAD work in 6400/4096ths of a
millivolt (or maybe the reciprocal of that) instead of directly in >millivolts.
It seems almost like an extreme caricature of what Dick
Gabriel called the New Jersey approach in "Worse Is Better" ( >https://www.dreamsongs.com/RiseOfWorseIsBetter.html ).
Well, of course what Jeff Fox (or dxforth) wrote may misrepresent the positions of Chuck Moore, although we also get some of his own
writings.
"Don't use local variables. Don't come up with new syntaxs for describing
them and new schemes for implementing them. You can make local variables
very efficient especially if you have local registers to store them in,
but don't. It's bad. It's wrong." - C.M.
On Monday, November 7, 2022 at 11:24:53 PM UTC+1, Anton Ertl wrote:
Marcel Hendrix <m...@iae.nl> writes:[..]
Chuck Moore's work on Forth is an example that is not
only comprehensible to others, but has inspired many others to use it,
adapt it to their needs, extend it, and do their own things with it.
And it scaled quite well. Thousands of people have used Forth.
That is meta-true for Forth as a language concept. But how many
engineers use CM's tools as-is in their daily work?
Mecrisp has some code for tidying the stack like that, but I thought it
was because the word being compiled didn't know where it was being
called from, so it had to present a consistent stack picture wherever
the caller was.
Ditzel's original CRISP cpu had a stack cache that may have been almost
as good as registers. I wonder if something that could come back someday.
if [C.M.'s] old (1971-1978) Forth had been incomprehensible, Forth
would not have seen the takeup it has seen. Dean Sanderson would have
been unable to design microForth, Seltzer and Ragsdale would have been
unable to do fig-Forth, and so on... And I think ... [C.M.]
considers the concepts more valuable than the code.
dxforth <dxforth@gmail.com> writes:
"Don't use local variables. Don't come up with new syntaxs for describing
them and new schemes for implementing them. You can make local variables >> very efficient especially if you have local registers to store them in,
but don't. It's bad. It's wrong." - C.M.
Reference needed.
But anyway, in 1971 Chuck Moore and Ken Thompson (Mr. New JerseyThere are, however, remarkable similarities between the Forth and Unix design. First, in Forth everything is a word. In Unix, everything is a file. Second, in Forth,
approach) were both working on minicomputers of the time, and Moore
created Forth, and Thompson created Unix. Both Forth and Unix became successful, with Forth switching to micros when they became powerful
enough, and Unix growing with the minis and switching to micros only
later in the 1980s. This already shows a difference.
On 9/11/2022 5:34 am, Anton Ertl wrote:
dxforth <dxforth@gmail.com> writes:
"Don't use local variables. Don't come up with new syntaxs for describing >>> them and new schemes for implementing them. You can make local variables >>> very efficient especially if you have local registers to store them in, >>> but don't. It's bad. It's wrong." - C.M.
Reference needed.
According to Google the source of the quote has been mentioned on c.l.f. on >at least 38 occasions over the years, most recently:
https://groups.google.com/g/comp.lang.forth/c/Wcn1OXpDSzI/m/dEyaxHSKAQAJ
https://groups.google.com/g/comp.lang.forth/c/Wcn1OXpDSzI/m/Q1fWbUCPAQAJ
The quote from Moore himself:
https://youtu.be/pSnNy7IpVMg?t=3192
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
if [C.M.'s] old (1971-1978) Forth had been incomprehensible, Forth
would not have seen the takeup it has seen. Dean Sanderson would have
been unable to design microForth, Seltzer and Ragsdale would have been
unable to do fig-Forth, and so on... And I think ... [C.M.]
considers the concepts more valuable than the code.
Did Sanderson etc. do their implementations by studying C.M.'s source
code, or did they simply reimplement its behaviour? I find Forth's
concepts to be mostly understandable. What I found hard to understand
was the actual Forth code written by C.M. that I looked at. I also
found fig-Forth to be hard to understand, if that matters. I'm
unfamiliar with microForth.
There are, however, remarkable similarities between the Forth and Unix design. >First, in Forth everything is a word. In Unix, everything is a file. Second, in Forth,
data is passed transparently and implicitly by the stack. In Unix, data can be >passed transparently and implicitly by pipes.
...
One reason for having locals was for implementing words that
have so many items in constant use that a pure-stack variant is
cumbersome.
[1] FAXPY ( ra f-x nstridex f-y nstridey ucount -- ) multiplies ra
with f-x and adds the result to f-y, where f-x and f-y are arrays and
ucount elements are accessed with strides nstridex and nstridey, >respectively. This is the Forth float variant of BLAS's SAXPY,
DAXPY, CAXPY and ZAXPY routines.
- anton
dxforth <dxforth@gmail.com> writes:
My point was it went from 4 locals to 6 for reasons of style. It may be C-style to expend resources this way (I wouldn't know)
In C these days, the extra locals wouldn't expend any resources in most cases, since the compiler would optimize them away.
but I doubt it's Moore's.
This I don't know. A traditional thread Forth interpreter (Moore's invention) is probably 10x slower than CODE doing the same thing, but
Moore only used CODE when he had to. If 9x extra compute cycles is
fine, why are a few memory cells a big deal?
On 9/11/2022 8:33 pm, Anton Ertl wrote:
...
One reason for having locals was for implementing words that
have so many items in constant use that a pure-stack variant is
cumbersome.
Both are complicated solutions AFAICS. One has lots of stack
operations and the other has lots of variables. They're as bad
as each other. Were folks to see that, they might look for
another solution.
In article <2022Nov...@mips.complang.tuwien.ac.at>,
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
<SNIP>
[1] FAXPY ( ra f-x nstridex f-y nstridey ucount -- ) multiplies raThis can be done with nested loops: I and J
with f-x and adds the result to f-y, where f-x and f-y are arrays and >ucount elements are accessed with strides nstridex and nstridey, >respectively. This is the Forth float variant of BLAS's SAXPY,
DAXPY, CAXPY and ZAXPY routines.
Rejecting local variables and then using I and J
(actually similar to adding a special A registers.)
that are a sort of register variables with a special purpose?
I have to admit that feels like cheating.
It makes the case for locals stronger, but local
TO-VALUEs have the same cludgy feeling as I and J.
In article <2022Nov9.103332@mips.complang.tuwien.ac.at>,
Anton Ertl <anton@mips.complang.tuwien.ac.at> wrote:
<SNIP>
[1] FAXPY ( ra f-x nstridex f-y nstridey ucount -- ) multiplies ra
with f-x and adds the result to f-y, where f-x and f-y are arrays and >>ucount elements are accessed with strides nstridex and nstridey, >>respectively. This is the Forth float variant of BLAS's SAXPY,
DAXPY, CAXPY and ZAXPY routines.
This can be done with nested loops: I and J
Rejecting local variables and then using I and J
(actually similar to adding a special A registers.)
that are a sort of register variables with a special purpose?
I have to admit that feels like cheating.
Paul Rubin <no.e...@nospam.invalid> wrote:
dxforth <dxf...@gmail.com> writes:
My point was it went from 4 locals to 6 for reasons of style. It may be C-style to expend resources this way (I wouldn't know)
In C these days, the extra locals wouldn't expend any resources in most cases, since the compiler would optimize them away.
but I doubt it's Moore's.
This I don't know. A traditional thread Forth interpreter (Moore's invention) is probably 10x slower than CODE doing the same thing, but
Moore only used CODE when he had to. If 9x extra compute cycles is
fine, why are a few memory cells a big deal?
I think origin of Forth explain this. In his book "PROGRAMMING
A PROBLEM-ORIENTED-LANGUAGE" Moore write about "programs with
input". In more clear language he wanted to have interactive
command processor. For processing user commands even minis
from 1970 and early micros have enough speed that you can lose
some (not too much, but factor of 10 is acceptable). OTOH
some minis were quite small. More writes about 4kB RAM, but
I think that he could put only very stripped down system on
such machine, full system that he outlines probably need
something between 8 and 16 kB RAM (FIG Forth executable is
slightly bigger than 6kB, but needs extra memory for block
buffers and for words defined in Forth).
Unix as OS, and of Forth as a programming language. Both had no
memory protection (Unix acquired virtual memory only with 3BSD in
1979), both acquired multi-tasking (and multi-user) pretty soon.
none albert schrieb am Mittwoch, 9. November 2022 um 14:59:51 UTC+1:...
In article <2022Nov...@mips.complang.tuwien.ac.at>,
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
<SNIP>
[1] FAXPY ( ra f-x nstridex f-y nstridey ucount -- ) multiplies ra
with f-x and adds the result to f-y, where f-x and f-y are arrays and
ucount elements are accessed with strides nstridex and nstridey,
respectively. This is the Forth float variant of BLAS's SAXPY,
DAXPY, CAXPY and ZAXPY routines.
Any 'reasonable' implementation would use CPU vector registers
when available. So any argumentation based on single scalar
stack or local elements (these are the only ones treated in the
Forth standard) barely counts.
With my non-standard array/buffer/matrix locals I could define this in
a one-liner:
: DAXPY { f: ra M: X Y == Y } ra X mscale Y m+ ;
\ mscale : vectorized scalar multiply
\ m+ : vectorized add
With my non-standard array/buffer/matrix locals I could define this inThe question is: How have you implemented MSCALE and M+? If it's not
a one-liner:
: DAXPY { f: ra M: X Y == Y } ra X mscale Y m+ ;
\ mscale : vectorized scalar multiply
\ m+ : vectorized add
in Forth, this indicates that Forth is not up to the task, which one
may consider to be ok, or which one may consider to be a challenge to
make Forth more versatile.
dxforth <dxforth@gmail.com> writes:
On 9/11/2022 8:33 pm, Anton Ertl wrote:
...
One reason for having locals was for implementing words that
have so many items in constant use that a pure-stack variant is
cumbersome.
Both are complicated solutions AFAICS. One has lots of stack
operations and the other has lots of variables. They're as bad
as each other. Were folks to see that, they might look for
another solution.
What would be your solution? Elizabeth Rather suggested assembler,
and I expect that's what Chuck Moore used before doing his own
hardware. On i21 he then added A and enhanced R.
...
Torturing a stack machine is hidden sadism. ;o)
For cherry-picked worst-case examples used to justify locals, if
hand-coded assembler does a better job than either stack or locals,
what's wrong with that?
The challenge had been how to bring this concept into Forth, so that the
code remains embeddable without having to pull in external algebra libraries.
Solution elements:
1) a matrix stack (similar to a dynamic string stack, nothing new)
matrix elements are just fat pointers to the "real" arrays/vectors in heap
2) global matrix values (they have a name)
3) matrix locals (they have names too)
4) some elementary words to operate with a.m. matrices (elementary linear
algebra, some I/O)
From a programmers perspective the most important element of these became >matrix locals. Not because they replaced equivalent matrix stack juggling, >but because they have NAMES!
On Thursday, November 10, 2022 at 1:27:32 AM UTC+1, dxforth wrote:
[..]
For cherry-picked worst-case examples used to justify locals, if
hand-coded assembler does a better job than either stack or locals,
what's wrong with that?
You need *very* "complicated" matrix-math to have a simple micro do
embedded control of the switched-mode power supplies that are
literally everywhere. One can set about implementing everything in
Forth from scratch, but it will take a single person a decade to get
a debugged library that is good enough to start experimenting
with the real problems at hand. (I am talking from experience).
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
if [C.M.'s] old (1971-1978) Forth had been incomprehensible, Forth
would not have seen the takeup it has seen. Dean Sanderson would have
been unable to design microForth, Seltzer and Ragsdale would have been
unable to do fig-Forth, and so on... And I think ... [C.M.]
considers the concepts more valuable than the code.
Did Sanderson etc. do their implementations by studying C.M.'s source
code, or did they simply reimplement its behaviour?
What I found hard to understand
was the actual Forth code written by C.M. that I looked at. I also
found fig-Forth to be hard to understand, if that matters. I'm
unfamiliar with microForth.
On 10/11/2022 4:22 am, Anton Ertl wrote:
What would be your solution? Elizabeth Rather suggested assembler,
and I expect that's what Chuck Moore used before doing his own
hardware. On i21 he then added A and enhanced R.
Firstly I don't see more variables and variable operations as a
solution. Apparently many do. When 99% of the world of the world's >languages is using variables both to solve its problems and craft
its functions, it's perhaps no surprise forthers will also come to
see them as a solution too - such is the conscious (and unconscious)
bias.
For cherry-picked worst-case examples used to justify locals, if
hand-coded assembler does a better job than either stack or locals,
what's wrong with that?
Anton Ertl schrieb am Mittwoch, 9. November 2022 um 23:09:30 UTC+1:...
With my non-standard array/buffer/matrix locals I could define this inThe question is: How have you implemented MSCALE and M+? If it's not
a one-liner:
: DAXPY { f: ra M: X Y == Y } ra X mscale Y m+ ;
\ mscale : vectorized scalar multiply
\ m+ : vectorized add
in Forth, this indicates that Forth is not up to the task, which one
may consider to be ok, or which one may consider to be a challenge to
make Forth more versatile.
Those exemplary vector words could be implemented in slow high-level Forth >but are actually primitives using AVX operators.
Solution elements:
1) a matrix stack (similar to a dynamic string stack, nothing new)
matrix elements are just fat pointers to the "real" arrays/vectors in heap
2) global matrix values (they have a name)
3) matrix locals (they have names too)
4) some elementary words to operate with a.m. matrices (elementary linear
algebra, some I/O)
For cherry-picked worst-case examples used to justify locals, if
hand-coded assembler does a better job than either stack or locals,
what's wrong with that?
dxforth <dxforth@gmail.com> writes:
For cherry-picked worst-case examples used to justify locals, if
hand-coded assembler does a better job than either stack or locals,
what's wrong with that?
The worst-case examples are where using pure stack ops causes pain so excruciating that it stops your work, unless some other approach is
found.
That's somewhat similar to my vector work (see references below and my incomplete implementation <https://github.com/AntonErtl/vectors>),
except that there are no vector locals (you could have them by using
V! on a cell-sized local buffer), and I am not sure whether your
global matrix corresponds to what I do by V!ing to a variable.
My implementation is based on generating GNU C code for the various
words from Forth, compiling this code and dynamically linking the
result; this code uses the GNU C extension <https://gcc.gnu.org/onlinedocs/gcc/extensions-to-the-c-language-family/using-vector-instructions-through-built-in-functions.html>.
There is also a slow path in standard Forth.
I find this state of affairs unsatisfying. I think that we should be
able to write such code in Forth and get competetive performance.
dxforth <dxforth@gmail.com> writes:
On 10/11/2022 4:22 am, Anton Ertl wrote:
What would be your solution? Elizabeth Rather suggested assembler,
and I expect that's what Chuck Moore used before doing his own
hardware. On i21 he then added A and enhanced R.
Firstly I don't see more variables and variable operations as a
solution. Apparently many do. When 99% of the world of the world's
languages is using variables both to solve its problems and craft
its functions, it's perhaps no surprise forthers will also come to
see them as a solution too - such is the conscious (and unconscious)
bias.
This does not tell me how you would solve the problem.
For cherry-picked worst-case examples used to justify locals, if
hand-coded assembler does a better job than either stack or locals,
what's wrong with that?
It's not Forth.
Blocks instead of files. I thought this one had resolved some decades
ago.
Paul Rubin wrote:
Blocks instead of files. I thought this one had resolved some decades
ago.
I'm using blocks in my day job right now. What do bare metal Forths
with things like flash storage do these days?
For instance, vector addition uses the type info
to select the suitable intrinsic instruction. Kind of dumb operator overloading,
but coded within the primitive, without generic Forth words like in your project
As to further developing your vector project, with all due respect, I doubt that this path leads to
more satisfactory results simply because there is way too much variety between CPU
generations and brands (and C compilers). I would leave those SIMD/AVX instructions
in their assembler or bultins/intrinsics world, but you may of course have other ideas
of which I am not aware.
Since when. ISTR Moore saying something to the effect portability
was a myth.
In article <tkkako$1sl1$1@gioia.aioe.org>, dxforth <dxforth@gmail.com> wrote:
<SNIP>
Since when. ISTR Moore saying something to the effect portability
was a myth.
He was wrong. gcc and gforth are portable to an undeniable extent.
Hell, programs written in ciforth are portable across a spectrum
of OSes.
The only point he can possibly contest, is that he don't think it's
worth the effort.
We recently discussed the compiling of pforth. There was a hitch and
it ultimately succeeded. This cannot be compared with writing pforth
from scratch.
Lars Brinkhoff schrieb am Freitag, 11. November 2022 um 08:40:38 UTC+1:
Paul Rubin wrote:
Blocks instead of files. I thought this one had resolved some decades
ago.
I'm using blocks in my day job right now. What do bare metal Forths
with things like flash storage do these days?
Blocks are still viable. Huffman-compressed text takes less storage.
"minf...@arcor.de" <minf...@arcor.de> writes:
For instance, vector addition uses the type infoI think I decided to let the programmer specify the type mainly to
to select the suitable intrinsic instruction. Kind of dumb operator overloading,
but coded within the primitive, without generic Forth words like in your project
follow Forth tradition, but also to avoid the need to decide what
happens when the programmer wants to mix types. E.g.,
( dfv1 dfv2 ) vdup 0e df>=vs ( dfv1 dfv2 xv ) andv ( dfv1 dfv3 ) df+v ( dfv4 )
When ANDV sees a vector of DFs (64-bit floats) and a vector of Xs
(64-bit integers), what should the result be? I as programmer know
that I want to mask the FP numbers here, but on another occasion I
might want to extract the mantissa fields or somesuch. The most
plausible result is that ANDV produces a bit-vector. When an
overloading +v sees a DF vector and a bit vector, what kind of
addition should it do? With DF+V, it's clear that it should do a DF
addition.
But this issue can be resolved (e.g., by explicitly specifying the
result type of the ANDV), and maybe overloaded operators are
preferable in the end. Normally Forth has few types (cells and
double-cells, sometimes with unsigned variants, characters in memory,
and one float type on the FP stack), while there are 10 different
vector types in my vector wordset; it may be that this is too much
mental load on the programmer and that the Forth system should take
care of that.
The way I use blocks is wasting 40%, compared to regular text files,I'm using blocks in my day job right now. What do bare metal ForthsBlocks are still viable. Huffman-compressed text takes less storage.
with things like flash storage do these days?
...
I'm using blocks in my day job right now. What do bare metal Forths
with things like flash storage do these days?
Lars Brinkhoff <lars.spam@nocrew.org> writes:
I'm using blocks in my day job right now. What do bare metal Forths
with things like flash storage do these days?
Blocks might be viable in some environments like that, but it seems like
a narrow niche. Implementing blocks in a Forth hosted under an OS that
has files seems silly.
Lars Brinkhoff <lars.spam@nocrew.org> writes:
I'm using blocks in my day job right now. What do bare metal Forths
with things like flash storage do these days?
Blocks might be viable in some environments like that, but it seems like
a narrow niche. Implementing blocks in a Forth hosted under an OS that
has files seems silly.
In a bare metal MCU Forth with flash storage and USB (Raspberry Pi Pico, >say), a FAT filesystem is very useful since it allows mounting the MCU
as a flash drive and transferring files super conveniently. It does
take up some code space but the Pico has plenty. A smaller processor
like an Arduino has less code space, but also too little RAM for block >buffers. You have to hunt around to find an MCU with just the right
specs to make blocks attractive.
Forth is typeless,
so for compound data (strings, structures, vector strides etc)
it can only "pass by reference" not "pass by value". Or one has to set
up special stacks for each data type which is cumbersome. And one has to >decide whether a <T>DUP just copies the reference address/pointer or also
the data payload which means slow cloning. A hypothetical vector wordset would >have to make such decisions, because SIMD instructions work with compound >groups of cells.
Using a FAT file-system on flash is the pinnacle of ridiculousness.
It is base on the notion of cylinder,track, sector subdivision.
There is a more sensible format:
Tape archive, from POSIX 1003.1-1990.
...
I had thought Polyforth was done by Chuck but maybe I'm wrong.
There's lots more, I've only scratched the surface. So I don't
understand why it is that locals in particular draw ire while everything
else skates by.
Somewhere in the talk of using factoring instead of locals, the need to
name the factors seems to have forgotten. If avoiding thinking up names
for the locals speaks in favor of stack juggling, the similar need to
name small factors shouldn't be ignored. (I usually name factors FOO.1, FOO.2 etc. though).
albert@cherry.(none) (albert) writes:
Using a FAT file-system on flash is the pinnacle of ridiculousness.
Everybody does it now. Buy a USB pen drive at the store and it will
already be formatted for FAT.
It is base on the notion of cylinder,track, sector subdivision.
Doesn't matter, that just gets mapped to a block number (LBA
translation). Windows systems still use FAT even though computers
mostly have SSD's now instead of spinning discs.
There is a more sensible format:
Tape archive, from POSIX 1003.1-1990.
It is not so easy to modify those, add new files, delete them, etc. It
is an archive format, not a file system.
albert@cherry.(none) (albert) writes:
Using a FAT file-system on flash is the pinnacle of ridiculousness.
Everybody does it now. Buy a USB pen drive at the store and it will
already be formatted for FAT.
Once again this demonstrates that a Forth in C can save a lot of pain.
Paul Rubin <no.e...@nospam.invalid> writes:
albert@cherry.(none) (albert) writes:
Using a FAT file-system on flash is the pinnacle of ridiculousness.
Everybody does it now. Buy a USB pen drive at the store and it willA USB stick (and also an SSD) has a flash translation layer (FTL) that emulates a system with 512-Byte blocks on the flash device. For a raw
already be formatted for FAT.
flash device (i.e., without FTL) FAT is not a good idea. It would be
slow and it would wear out the FAT (meta-data) blocks quickly. One
file system designed for raw flash is JFFS2.
It's been reported Polyforth was a combined effort between several
Forth Inc staff and Moore. Moore would later go on to say:... "Forth
doesn't need to be complicated. Classic Forth started out simple..."
Perhaps because of the propaganda that 'stack juggling' is rife in forth
and locals somehow solve it.
[FAT] It does matter: complicated, different formats, and royalties
over 32 Gbyte to be payed to Microsoft (as I remember correctly).
You will be hard pressed to find a FAT within 800 words of code.
Pretty please point me to a FAT stack that can run on a
single board computers.
It is not so easy to modify those, add new files, delete them, etc. It
is an archive format, not a file system.
Most pen drive are used as an archive anyway.
: DELETE-FILE '(OPEN-EXISTING-FILE) ...
Was that hard?
I guess you mean that it is not fit to replace a real
disk, with random deletions and creations *all the time*.
Might I remember you how the track record is from FAT
under these circumstance?
I rather write a defragger for POSIX 1003.1-1990.
dxforth <dxforth@gmail.com> writes:
It's been reported Polyforth was a combined effort between several
Forth Inc staff and Moore. Moore would later go on to say:... "Forth
doesn't need to be complicated. Classic Forth started out simple..."
Ok, but did classic Forth have multitasking? Is Moore known to have
approved of it, or maybe disapproved? Do the current Forth purists have
a view on the matter?
Perhaps because of the propaganda that 'stack juggling' is rife in forth
and locals somehow solve it.
I didn't think it was under debate that stack juggling is confusing.
Locals are one approach to dealing with it, maybe a barbaric one. The
purist alternative is to instead use finer grained factoring.
Both of those approaches introduce more names into the program.
So whatever drawbacks locals might have, "they make the programmer think up more names" doesn't seem to be one. In fact, locals usually have
re-usable temporary names like "a" and "b", while factor names usually
have to be globally unique.
Paul Rubin <no.email@nospam.invalid> writes:
albert@cherry.(none) (albert) writes:
Using a FAT file-system on flash is the pinnacle of ridiculousness.
Everybody does it now. Buy a USB pen drive at the store and it will >>already be formatted for FAT.
A USB stick (and also an SSD) has a flash translation layer (FTL) that >emulates a system with 512-Byte blocks on the flash device. For a raw
flash device (i.e., without FTL) FAT is not a good idea. It would be
slow and it would wear out the FAT (meta-data) blocks quickly. One
file system designed for raw flash is JFFS2.
- anton
dxforth <dxforth@gmail.com> writes:
It's been reported Polyforth was a combined effort between several
Forth Inc staff and Moore. Moore would later go on to say:... "Forth
doesn't need to be complicated. Classic Forth started out simple..."
Ok, but did classic Forth have multitasking? Is Moore known to have
approved of it, or maybe disapproved? Do the current Forth purists have
a view on the matter?
Perhaps because of the propaganda that 'stack juggling' is rife in forth
and locals somehow solve it.
I didn't think it was under debate that stack juggling is confusing.
Locals are one approach to dealing with it, maybe a barbaric one. The
purist alternative is to instead use finer grained factoring.
Both of those approaches introduce more names into the program. So
whatever drawbacks locals might have, "they make the programmer think up
more names" doesn't seem to be one. In fact, locals usually have
re-usable temporary names like "a" and "b", while factor names usually
have to be globally unique.
In article <87v8ni1lf8.fsf@nightsong.com>,
Paul Rubin <no.email@nospam.invalid> wrote:
dxforth <dxforth@gmail.com> writes:
It's been reported Polyforth was a combined effort between several
Forth Inc staff and Moore. Moore would later go on to say:... "Forth
doesn't need to be complicated. Classic Forth started out simple..."
Ok, but did classic Forth have multitasking? Is Moore known to have
approved of it, or maybe disapproved? Do the current Forth purists have
a view on the matter?
I think this is a moot question. [...]
You will be hard pressed to find a FAT within 800 words of code.
Pretty please point me to a FAT stack that can run on a
single board computers.
Lars Brinkhoff <lars.spam@nocrew.org> writes:
I'm using blocks in my day job right now. What do bare metal Forths
with things like flash storage do these days?
Blocks might be viable in some environments like that
In a bare metal MCU Forth with flash storage and USB (Raspberry Pi Pico, >say), a FAT filesystem is very useful since it allows mounting the MCU
as a flash drive and transferring files super conveniently.
Anton Ertl schrieb am Sonntag, 13. November 2022 um 19:51:39 UTC+1:
A USB stick (and also an SSD) has a flash translation layer (FTL) that
emulates a system with 512-Byte blocks on the flash device. For a raw
flash device (i.e., without FTL) FAT is not a good idea. It would be
slow and it would wear out the FAT (meta-data) blocks quickly. One
file system designed for raw flash is JFFS2.
Such deep level details are usually hidden from the unsuspecting user
through a suitable API library
"minf...@arcor.de" <minf...@arcor.de> writes:
Anton Ertl schrieb am Sonntag, 13. November 2022 um 19:51:39 UTC+1:
A USB stick (and also an SSD) has a flash translation layer (FTL) that
emulates a system with 512-Byte blocks on the flash device. For a raw
flash device (i.e., without FTL) FAT is not a good idea. It would be
slow and it would wear out the FAT (meta-data) blocks quickly. One
file system designed for raw flash is JFFS2.
Such deep level details are usually hidden from the unsuspecting user >through a suitable API librarySure you can hide the details from the user in some way: The FTL
presents the same interface as a disk drive to the user, and a file
system like JFFS2 presents the usual POSIX file system interface
(open, close, read, write, etc.).
But in this case the details are important if you want to get
performance and longevity from the device, so I think that the disk
interface is not the way to go. The file system interface is better,
but a file system like JFFS2 is quite complex.
This seems like a situation where a new interface might offer
significant benefits in performance, device longevity, and
implementation simplicity compared to what we have now.
My program tmanx manages to play different instruments parallel, while filling a number of high priority queues that are handled in
parallel. That is a tailor made solutions for multi tasking on two
priority levels. That is in the spirit of Forth.... In fact ciforth
has pre-emptive and cooperative multi tasking in its library and
neither are used in tmanx.
Not: inventing multi tasking, add bells and whistles and lean back.
"What are we going to do with it?"
Names have to mean something. a x y z are merely placeholders.
In fact locals let you simplify Forth. Forth's stack primitives (OVER,
DROP, and friends) have to be implemented as CODE because there is no
good way to write them in Forth. But with locals it is trivial:
: OVER { a b } a b a ;
: DROP { a } ;
: OVER { a b } a b a ;And where did the locals come from if not via CODE and Forth stack
: DROP { a } ;
primitives - virgin birth?
I don't think that Forth blocks/screens, which were designed for disk
drives are a good abstraction for flash, which has different
properties than the devices that blocks were designed for
source code storage in flash with single-byte write granularity (and a
16KB erase block size
The more typical setup is to have the permanent storage on the big
computer, talk to the MCU, and supply the source code stored on the
big computer through the same interface.... No need for a FAT on the
MCU in this case.
dxforth <dxforth@gmail.com> writes:
: OVER { a b } a b a ;And where did the locals come from if not via CODE and Forth stack
: DROP { a } ;
primitives - virgin birth?
The same place the Forth interpreter itself came from, i.e. typically metacompilation. I guess virgin birth could be a metaphor for that.
In fact locals let you simplify Forth. Forth's stack primitives (OVER,
DROP, and friends) have to be implemented as CODE because there is no
good way to write them in Forth. But with locals it is trivial:
: OVER { a b } a b a ;
: DROP { a } ;
And where did the locals come from if not via CODE and Forth stack primitives -
virgin birth?
Coroutines are another useful technique. Knuth vol. 1 made the case for
them being better than subroutines all the way back in 1968. They are >considered a little bit esoteric in most languages even now, but I
notice that the GreenArrays chip has a machine instruction for a
coroutine switch, so I take that as evidence that Moore found coroutines
to be worthwhile.
albert@cherry.(none) (albert) writes:
My program tmanx manages to play different instruments parallel, while
filling a number of high priority queues that are handled in
parallel. That is a tailor made solutions for multi tasking on two
priority levels. That is in the spirit of Forth.... In fact ciforth
has pre-emptive and cooperative multi tasking in its library and
neither are used in tmanx.
Well, if that application was tailor made for multi-tasking, why didn't
you use it?
Not: inventing multi tasking, add bells and whistles and lean back.
"What are we going to do with it?"
Coroutines are another useful technique. Knuth vol. 1 made the case for
them being better than subroutines all the way back in 1968. They are >considered a little bit esoteric in most languages even now, but I
notice that the GreenArrays chip has a machine instruction for a
coroutine switch, so I take that as evidence that Moore found coroutines
to be worthwhile.
Names have to mean something. a x y z are merely placeholders.
You mean like the loop indexes i j k that are built into the language,
or seen all the time in mathematics? They are perfectly legitimate,
just like you'd use n to denote a quantity of something, or x as the arg
to your square root function. Or names like "length" or "height" or >"tax-amount" are perfectly meaningful and can be used as local names in
as many different word definitions as you like, but if they become word
or VARIABLE names, they have to be globally unique, not so nice.
In fact locals let you simplify Forth. Forth's stack primitives (OVER,
DROP, and friends) have to be implemented as CODE because there is no
good way to write them in Forth. But with locals it is trivial:
: OVER { a b } a b a ;
: DROP { a } ;
and so on. Fwiw I don't see benefit to using more meaningful names for
those locals. I don't even know what names would be more meaningful
than just a and b.
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
I don't think that Forth blocks/screens, which were designed for disk
drives are a good abstraction for flash, which has different
properties than the devices that blocks were designed for
Maybe this is right, though it could be that the flash included in MCU's
has friendlier characteristics (though smaller capacity) than the very
dense NAND flash used in SSD's, SD cards, and the like.
And if the idea
is to use the blocks for program storage, write wear shouldn't be a big >issue, even with no sector remapping.
You only use write cycles when
you update the program. Having an active, frequently updated database
in flash could be more of a problem.
source code storage in flash with single-byte write granularity (and a
16KB erase block size
If you can reserve a 16KB block S for scratch storage, you can do an >erase-copy-erase-copy operation to update any smaller block. It's ugly
but it probably suffices for code editing and the like.
FRAM as found in some TI MSP430 processors is a super nice medium for
blocks of course: https://www.ti.com/tool/MSP-EXP430FR5994
Unfortunately, non-MSP430 FRAM processors aren't currently available.
I hope that changes someday.
The more typical setup is to have the permanent storage on the big
computer, talk to the MCU, and supply the source code stored on the
big computer through the same interface.... No need for a FAT on the
MCU in this case.
That sounds like it needs special software on the big computer, which is
a disadvantage compared to simply writing out files with your favorite >editing program. I guess it is workable though.
Forth's stack primitives (OVER,
DROP, and friends) have to be implemented as CODE because there is no
good way to write them in Forth. But with locals it is trivial:
: OVER { a b } a b a ;
: DROP { a } ;
and so on. Fwiw I don't see benefit to using more meaningful names for >>those locals. I don't even know what names would be more meaningful
than just a and b.
Seriously? You use a locals package that has DROP and OVER all
over the place ... to define DROP and OVER ?
Paul Rubin <no.email@nospam.invalid> writes: >>anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
I don't think that Forth blocks/screens, which were designed for disk
drives are a good abstraction for flash, which has different
properties than the devices that blocks were designed for
Maybe this is right, though it could be that the flash included in MCU's >>has friendlier characteristics (though smaller capacity) than the very >>dense NAND flash used in SSD's, SD cards, and the like.
They still have very different characteristics from the disk drives
that blocks/screens were designed for. The blocks/screen interface
does not give you all the benefits of the nice flash, while at the
same time introducing inefficiencies to work around the mismatch
between the screen/block interface and the characteristics in other
areas.
And if the idea
is to use the blocks for program storage, write wear shouldn't be a big >>issue, even with no sector remapping.
Maybe. But even for (source?) program storage, why stick with the
block interface? That's just intellectual lazyness from the
traditionalists; they are not even being purists here, because Forth
means striving for a simple, efficient solution (and for purists: even
when it's not necessary), not sticking to an outdated interface.
You only use write cycles when
you update the program. Having an active, frequently updated database
in flash could be more of a problem.
So, basically, the blocks interface is a bad fit, but if you use it
rarely enough, you can live with it.
source code storage in flash with single-byte write granularity (and a
16KB erase block size
If you can reserve a 16KB block S for scratch storage, you can do an >>erase-copy-erase-copy operation to update any smaller block. It's ugly
but it probably suffices for code editing and the like.
The first MCU I found that fit "from ST, 1MB Flash" is the
STM32F405/415, which has 192KB RAM. You suggest to waste 16KB of that
on the blocks interface (and having a write amplification factor of
16, which means that the writes are 16 times slower than with a better >interface, and the flash wears out 16 times faster.
Well, at least UPDATE and SAVE-BUFFERS is separated in the blocks
interface, so you have the chance to update multiple blocks in the
same erase block before erasing and writing them with one
SAVE-BUFFERS. But of course you also could need to save the buffer
because you need it for getting another block into RAM.
And this is the kind of nice small non-NAND flash that you get with
MCUs:
* You can read directly from it, which is not well utilized with the
blocks interface; note that with that interface you even have to
copy into RAM when you want to read from the block, because that's
what the interface requires: BLOCK gives you the address of a RAM
buffer that you can the write to several times.
* You can write bytewise to it, which is also not well utilized with
the blocks interface, which only supports writing a block at a time.
* You can erase 16KB at a time, which does not fit the 1KB
screen/blocks interface well, as discussed above.
Paraphrasing the
<https://en.wikipedia.org/wiki/Law_of_the_instrument>: If all you have
is traditional Forth, everything looks like a nail.
FRAM as found in some TI MSP430 processors is a super nice medium for >>blocks of course: https://www.ti.com/tool/MSP-EXP430FR5994
FRAM is a super nice medium for everything, because it is a persistent
RAM. Of course you can let most of its benefits go to waste by using
a blocks interface on it, but why would you do that? Just treat it as
RAM.
Unfortunately, non-MSP430 FRAM processors aren't currently available.
I hope that changes someday.
Doubtful. Non-flash persistent memory was the coming thing of the
2010s (one of the selling points of the 2015 Skylake was that it
supports Optane memory), but that future has not arrived. Flash
progressed faster than the competing technologies, and apparently it
is outcompeting even FRAM (or maybe battery-backed SRAM is
outcompeting FRAM). MSP430 is on the way out, and even among MSP430
MCUs there are few with FRAM.
The more typical setup is to have the permanent storage on the big
computer, talk to the MCU, and supply the source code stored on the
big computer through the same interface.... No need for a FAT on the
MCU in this case.
That sounds like it needs special software on the big computer, which is
a disadvantage compared to simply writing out files with your favorite >>editing program. I guess it is workable though.
You write files with your favourite editing program on the big
computer, and when you type "include foo.4th" in the Forth console,
the file is read on the big computer and transferred to the MCU. You
need some communications program anyway, because you need to control
the Forth system on the MCU. Traditionally the console worked across
a serial connection (and the serial connection did not present a
mass-storage interface to the OS on the big computer), but I don't see
any advantage in switching to a setup where you use some of the flash
on the MCU for a FAT file system, and access that as USB mass storage,
and the Forth system on the MCU loads from that.
- anton
[coroutines] Which instruction do you mean? From what I know about
the Greenarrays stuff, I very much doubt it
And if the idea is to use the blocks for program storage, write wear >>shouldn't be a big issue, even with no sector remapping.Maybe. But even for (source?) program storage, why stick with the
block interface?
You only use write cycles when you update the program. Having anSo, basically, the blocks interface is a bad fit, but if you use it
active, frequently updated database in flash could be more of a problem.
rarely enough, you can live with it.
If you can reserve a 16KB block S for scratch storage, you can do an >>erase-copy-erase-copy operation to update any smaller block....
The first MCU I found that fit "from ST, 1MB Flash" is the
STM32F405/415, which has 192KB RAM. You suggest to waste 16KB of that
on the blocks interface
which means that the writes are 16 times slower than with a better
interface, and the flash wears out 16 times faster.
Paraphrasing the
<https://en.wikipedia.org/wiki/Law_of_the_instrument>: If all you have
is traditional Forth, everything looks like a nail.
FRAM is a super nice medium for everything... Just treat it as RAM.
MSP430 is on the way out, and even among MSP430 MCUs there are few
with FRAM.
You write files with your favourite editing program on the big
computer, and when you type "include foo.4th" in the Forth console,
the file is read on the big computer and transferred to the MCU. You
need some communications program anyway, because you need to control
the Forth system on the MCU.
I don't see any advantage in switching to a setup where you use some
of the flash on the MCU for a FAT file system, and access that as USB
mass storage, and the Forth system on the MCU loads from that.
...
At that point, you might as well have a tethered Forth where
the compiler is also on the host side.
Works for the forth vendors. Arduino users would be chomping at
the bit to have one of those :)
anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:
Unix as OS, and of Forth as a programming language. Both had no
memory protection (Unix acquired virtual memory only with 3BSD in
1979), both acquired multi-tasking (and multi-user) pretty soon.
Unix had memory protection on the PDP-11, long before it got virtual
memory. The PDP-11/40 and friends had memory segments with protection registers, so processes couldn't clobber each other or reach into the
kernel. With earlier models (11/20, PDP-7 etc.) you could crash a whole timesharing system by having a pointer bug in your program. I thought
that Unix had multi-tasking from the beginning, but am not sure.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 502 |
Nodes: | 16 (2 / 14) |
Uptime: | 219:49:56 |
Calls: | 9,878 |
Calls today: | 6 |
Files: | 13,791 |
Messages: | 6,205,956 |