dxf...@gmail.com writes:
>> At least it's complete and less complex, but again, it does not work
>> in all cases, e.g.:
>>
>> 1 cells 1 cells field foo drop
>> create bar 5 , 6 ,
>> defer flip ' foo is flip
>> : bla bar flip @ postpone literal ; immediate
>> : blubb bla ;
>> 0 blubb cr . . \ prints 6 0 with a correct FIELD
>>
>
>Neither can DO LOOP be used in every imaginable
>situation, yet used it still is.
>State-smartness is a tool like any other. If
>you get yourself into trouble through ignorance,
>shall you condemn the tool and expend resources
>avoiding it - or do you learn from your mistake and thereafter use the tool appropriately?
If the problems of STATE-smartness just bit the programmer who uses
it, I would have no problem with it.
But the problem with STATE-smartness is that the trap tends to spring
very far, both in time and space, from where it was set.
E.g. consider the example above, and consider that the individual
pieces are parts of bigger libraries or programs.
Programmer A defines FIELD.
Programmer B defines FOO.
Programmer C defines BAR.
Programmer D defines BLA.
Programmer E writes "' foo is flip".
Programmer F defines BLUBB, and in testing, realizes that it does not
work as expected.
Who should fix the bug? A, B, C, D, E, or F? And how should it be
fixed?
Did they document the STATE-smartness of FIELD's children, of FOO, and
the potential STATE-smartness of FLIP, and of BLA? Now some Forthers
don't document their programs, and they hold the position that users
of a piece of code should read the source and discover by themselves
the traps (such as STATE-smartness) that this code's programmer put in
the code, and its effect on the applicability of this piece of code.
In that position F is at fault for not having read and completely
understood all the code that is used in the definition of BLUBB. The
bugfix? He cannot use FIELD, FOO, BAR, and BLA from the libraries in
pristine condition, so he either has to change some of these libraries
(so from then on he has to maintain them himself), or write BLA and
all that it uses by himself. Given that, in such a world, these
libraries probably contain other traps, too, the latter looks like the
better solution.
So if STATE-smartness is a tool like any other, we have an environment
where we better don't use libraries (is that what you mean with "learn
from your mistake and thereafter use the tool appropriately"?).
Not using libraries is actually Chuck Moore's position. Ironically,
Chuck Moore eliminated STATE from his Forths, certainly from cmForth,
but from what I read here, also from polyForth. So he apparently did
not consider STATE-smartness a legitimate tool, at least after a
while.
In any case there are those of us who think that it is useful to be
able to use libraries. Then we need an environment where the
libraries have simple and universal interfaces, not interfaces full of
traps and caveats. And in such an environment STATE-smartness is
inappropriate, because it leads to traps and caveats. And "I have not
had any problems yet" is not good enough if you program for general
consumption.
And in the case of FIELD there are much better alternatives:
A straighforward (and shorter) way to write FIELD is:
: field ( offset1 n "name" -- offset2 )
create over , +
does> ( addr1 -- addr2 )
@ + ;
Disadvantages of this implementation that the STATE-smart
implementations try to fix:
1) The @ cannot be optimized away, which costs cycles on some CPUs.
2) Simple Forth implementations won't inline the call to children of
FIELD.
The implementation at the start of the thread
: field \ offset1 n "name" -- offset2 ; addr1 -- addr2
over >r
: r> postpone literal postpone + postpone ;
+
;
solves problem 1, but not problem 2. Is problem 2 worth solving?
Maybe, but is it worth to exchange it for the problems caused by
STATE-smartness? Not in a library for general consumption.
What else can we do? In current development Gforth, you can write
: field ( offset1 n "name" -- offset2 )
\ you must not change the body of "name"
create over , +
[: @ + ;] set-does> ( addr1 -- addr2 )
[: >body @ ]] literal + [[ ;] set-optimizer ;
This solves both problem 1 and 2, and each child of FIELD consumes
less memory than in the definition from the start of the thread.
There is someone who prefers
OPT: <code>
to
[: <code> ;] SET-OPTIMIZER
With OPT: and DOES>, and without ]] ... [[, the definition would look
like this:
: field1 ( offset1 n "name" -- offset2 )
create over , +
does> ( addr1 -- addr2 )
@ + ;
: field ( offset1 n "name" -- offset2 )
\ you must not change the body of "name"
field1
OPT:
>body @ postpone literal postpone + ;
I leave it to you to decide which notation is better, but in any case,
both definitions are equivalent and have the same advantages when used.
Do we need STATE-smartness for implementing FIELD? No!