In the books that I've read and want to read, there is very little
mention about heap allocation and collection datatypes (eg. lists and
maps). I do know from searching around that there are Forth libraries
for this. But it seems that they are not strictly necessary (since the
beginner books don't mention them).
This is fascinating to me, and it's the major reason that I'm
interested in Forth to start with. But I'm currently lost on how to
write nontrivial programs at a high abstraction level without using
heap allocation and collections.
My biggest difficulty right now is to avoid both treating Forth like C
(ie. writing at a very low abstraction level) and also to avoid
treating Forth like Lisp (ie. writing at a high abstraction level but
having to use all the heap allocation libraries and collection
libraries).
Is there a way I can write both at a high abstraction level and also
not have to use heap allocation and object-oriented libraries? I get
the sense that this is possible, because lots of people like the
abstraction capabilities of Forth, without necessarily using object-
oriented libraries and heap allocation.
-Patrick
It really would be helpful if you told us what system you're using and
what books you've read so far. Also, I do encourage you to continue
your reading!
> In the books that I've read and want to read, there is very little
> mention about heap allocation and collection datatypes (eg. lists and
> maps). I do know from searching around that there are Forth libraries
> for this. But it seems that they are not strictly necessary (since the
> beginner books don't mention them).
>
> This is fascinating to me, and it's the major reason that I'm
> interested in Forth to start with. But I'm currently lost on how to
> write nontrivial programs at a high abstraction level without using
> heap allocation and collections.
Many, many very non-trivial programs have been written in Forth without
using heap allocation and collections! This will take some getting used
to, I'm sure, but it's really a matter of style. Forth is a simple
system in concept, and both compact and fast in use.
There do exist implementations for such things (ANS Forth introduced a
simple heap allocation scheme, for example), but they are not necessary
for most programming.
> My biggest difficulty right now is to avoid both treating Forth like C
> (ie. writing at a very low abstraction level) and also to avoid
> treating Forth like Lisp (ie. writing at a high abstraction level but
> having to use all the heap allocation libraries and collection
> libraries).
>
> Is there a way I can write both at a high abstraction level and also
> not have to use heap allocation and object-oriented libraries? I get
> the sense that this is possible, because lots of people like the
> abstraction capabilities of Forth, without necessarily using object-
> oriented libraries and heap allocation.
As a beginner, you should start at a low abstraction level and build
your working vocabulary of Forth commands and techniques, including
stack management. Use simple exercises at the outset. Master the basic
skills and get comfortable with plain Forth. One does not start flying
lessons in a 747; a simple plane is much easier to learn in.
As you become more comfortable with the basics, you can begin to think
about the specific kinds of things you need for your primary application
domain. Write programs to do those things. Look at the features these
programs have in common, and factor them into your own personal toolkit.
In the advanced stages of an application, one can work at a very high
abstraction level, but that isn't where one begins.
There are useful things around: there is a pretty advanced math
library, for example, and most of the modern Forth systems available
include a lot of capabilities. They vary from one system to another.
For example, most offer some kind of OOP system (although they differ,
and are far from standardized!). When you have a good mastery of basic
Forth look around and pick the system that has more of the kinds of
toolsets you're looking for, is well-documented and has the kind of user
interface you like. Both FORTH, Inc. and MPE offer free evaluation
versions of their systems.
Cheers,
Elizabeth
--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com
"Forth-based products and Services for real-time
applications since 1973."
==================================================
You may begin with "structures".
It is a basic abstraction tool.
-Charles
: +field ( n <"name"> -- ) \ Exec: addr -- 'addr
create over , + does> @ + ;
0
cell +field x
cell +field y
constant PointStruct
PointStruct
cell +field color
constant PixelStruct
create pixel PixelStruct allot
10 pixel x !
20 pixel y !
$AABBCC pixel color !
"CuppoJava" <patrick...@hotmail.com> a �crit dans le message de
news:
abf24d16-2ef5-4316...@j19g2000yqk.googlegroups.com...
This may be contrary to what you could read in OOP/OOD books, but
modules that include interrelated functions working at the same level
("lexicons") are a very powerful expressive means.
For example, you want a device attached to some ports of the CPU to do
something. First, you have to decide how this all will be done. This
is top-down design. Then, you begin to implement starting from the
lowest level. Most likely, you will start with coding the words that
access the required ports in assembly. This is the first level. Now,
you can write words that make the device perform elementary actions
(like start motor, read status, etc.) This is the second level. Then,
you use the elementary actions from level 2 to build a set of
meaningful actions, which constitutes the level 3. And so on.
It is important to keep the definitions as simple as possible. A
definition expresses a notion in your vision of the problem. So,
developing the project, you build a straightforward mapping of
application domain concepts onto the software components. (Or, build
such structure of software components that it naturally maps...)
If you know a Lisp, the idea must be familiar for you.
Let us compare this to the OO approach. A project starts with a desing
phase; some guy creates a class for each noun in the application
domain, and some classes for qualified nouns. It is usually useless to
tell the guy that not each noun must become a class in the code. I
mean, a relatively high percentage of classes is not really needed.
(For example, they build a tree structure derived from input data
instead of processing the input data directly, using its regularity.)
Yes, it depends on whose design it was... So class stubs are generated
and the coders begin to work. But whoever the coders are, and whatever
they do, there already is a mapping of application domain notions onto
the software components. Some guys believe that only OOP can give them
that. Usually their books do not include any references to Scheme/Lisp
or Forth.
By the way, many OO design patterns are applicable in Forth without
any OO.
>
> My biggest difficulty right now is to avoid both treating Forth like C
> (ie. writing at a very low abstraction level) and also to avoid
> treating Forth like Lisp (ie. writing at a high abstraction level but
> having to use all the heap allocation libraries and collection
> libraries).
Whatever language you use, you should first write on the low level,
then on higher levels, up to the very top. Dr Baranoff has described a
C project written as if it was in Forth. Small functions etc. Small
size of executable for the implemented functionality.
>
> Is there a way I can write both at a high abstraction level and also
> not have to use heap allocation and object-oriented libraries? I get
> the sense that this is possible, because lots of people like the
> abstraction capabilities of Forth, without necessarily using object-
> oriented libraries and heap allocation.
>
> -Patrick
One builds sets of words that reflect the application domain notions.
I can propose an exercise: implement a text-mode video game in Forth.
For example, "badminton" -- but it's a strange badminton because the
shuttlecock gets reflected from the walls. Two rackets for two
players, one (or two?) of which may be the computer. Everything is
drawn with symbols like # and @.
PAGE ( -- ) clear screen
AT-XY ( x y -- ) the text cursor goes to (x,y)
MS ( n -- ) milliseconds of delay
KEY ( -- c ) read a keypress, wait if not available
KEY? ( -- flag ) true if a keypress is available
Your system may provide a word to read the clock, but there is no
standard name for that functionality.
Such games worked decades ago on 8-bit i8080 CPUs at 1 MHz. The funny
thing is that nobody tried to optimize the speed of text mode output,
so a 2GHz AMD64 will have the same bottlenecks... :)
And, back to philosophy: the word is what it does.
--
practice is the best way to enlightement
May I suggest projecteuler.net ? There are far too few Forth
programmers there. You can start with easy programs, and
proceed to challenges. Great fun!
heap allocation goes like
12 , 34 ,
200 CELLS ALLOT
I have managed 100+ of those problems with a very basic Forth
(Some I've done in Python, but that just means that I'm
learning Python.)
<SNIP>
>
> -Patrick
Groetjes Albert
--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst
I had the impression that ProjectEuler is more for small numerical
algorithm coding, so I haven't looked into it yet.
-Patrick
The predominate domain for Forth is embedded systems. And often, most
embedded systems tend toward purpose-built systems (verses generic
systems like a desktop machine) that are scaled for the specific
problem they are trying to solve. So, the targets for Forth tend to
be resource limited systems.
In such systems, dynamic allocation of memory isn't something one
often needs. The embedded system now sitting to my right is an
example of this-- it can be one of up to eight units on a network.
There will never be more and this is by design. So, there is little
value in dynamically allocating memory to represent the other units on
the network; I just allocate a simple vector statically when the
program starts. This means that I know ahead of time how much memory
I'm going to need, I don't have the cost of having a deallocator in my
system, and in the case of garbage-collecting systems, I don't have to
worry about how the garbage collector might screw around with the real-
time aspects of my system. Of course, there are systems where such
this isn't possible, but again in embedded systems, you're often
designing around known limits and you can exploit that fact to design
simpler systems.
As for generic collections, the typical Forth programmer will avoid
generic solutions and would instead design a specific solution. And
as with following any ideology, that has both positive and negative
consequences. The positive is that code that is specific to the
solution is usually going to be faster and smaller. And again, given
the traditional targets for Forth, faster and smaller often matters.
The negative is that sometimes those generic collections are key
components of languages that offer them, and so they are highly
optimized. So while designing a specific collection class may give
huge space/time benefits over dumb, non-optimal generic solutions,
there is likely to be a diminishing return against a library that
offers more tight, optimized code.
An example of this would be "tables" in Lua. Lua is like a lot of
scripting languages in that it offers maps (aka dictionaries, hashes,
associative arrays, etc.). In Lua, these tables are used for both
arrays and maps, but unlike a lot of languages, these maps are smart.
If you treat a table as an array, there is code to notice this and it
actually stores your data as an array so you get the speed benefits of
arrays. If you treat a table as a map, it notices and takes a more
traditional approach. There is of course a cost to this intelligence,
but it isn't much. The point here is that a Forth programmer who
thought "ah, I'll implement this as an array and get a performance
boost" wouldn't get much of a boost for their effort, and that time
wasted might be spend more usefully on other things.
> This is fascinating to me, and it's the major reason that I'm
> interested in Forth to start with. But I'm currently lost on how to
> write nontrivial programs at a high abstraction level without using
> heap allocation and collections.
Well, the key is that you'll be creating your own abstractions and
then using them, instead of taking canned generic abstractions (like a
map) and wrapping your abstraction around that. Your typical
programmer using a language like Java or C++ or C# would take a
generic container class and through either inheritance (is-a) or
embedded inside (has-a) create an interface around that generic
collection (to restrict, to validate, to define policy, etc.). Your
typical Forth programmer might end up with a similar interface around
the collection for similar reasons, but their collection is more
likely something built on simpler structures (vectors, linked lists,
trees) coded by hand.
> My biggest difficulty right now is to avoid both treating Forth like C
> (ie. writing at a very low abstraction level) and also to avoid
> treating Forth like Lisp (ie. writing at a high abstraction level but
> having to use all the heap allocation libraries and collection
> libraries).
Despite what people here like to think, Forth and C programmers are
more alike than different. At least they are when you compare
embedded systems programmers using Forth and embedded systems
programmers using C. But comparing things that are alike in this
newsgroup isn't popular, so you'll typically see comparisons between
the fearless low-level Forth programmer and the C programmer who is
constrained by an omnipotent operating system and libraries they don't
fully understand. Get used such apples and oranges comparisons here,
because they are plentiful.
Regardless, if your work isn't in embedded systems, you might consider
a Forth-like language instead of Forth. Factor as a language does
give you a nice combination of high-level abstractions (including
automatic memory management) but still giving you low-level access if
you need.
> Is there a way I can write both at a high abstraction level and also
> not have to use heap allocation and object-oriented libraries? I get
> the sense that this is possible, because lots of people like the
> abstraction capabilities of Forth, without necessarily using object-
> oriented libraries and heap allocation.
Again, the core notion to keep in your head is that a Forth programmer
tends to do it themselves. Nothing prevents you from building
whatever high-level abstractions you want and then coding your
solution in terms of those abstractions. But the key is that you're
going to be the one who does that building. And that means you're
going to have to understand the mechanisms behind those abstractions.
A Java programmer doesn't have to know anything about hashing and
resolving collisions in a map in order to use one. A Forth programmer
does, because he's going to be implementing it. A Java programmer may
not understand the cost of using a map. A Forth programmer will.
As for object orientation, the positives (and negatives) of an object-
oriented approach apply equally well to Forth as to any other
language. The Forth community (at least here in comp.lang.forth)
tends to be hostile to object orientation, but not usually for good
reasons. You can see this in the kinds of knee-jerk responses that
often pop up here, from people who don't understand proper modeling
("I created a ball object with a throw method!") or from people who
confuse a language for a paradigm ("C++ objects are complex
monstrosities, so all objects are"), or from people who confuse bad
implementation with a paradigm ("I saw a OOP system with thousands of
classes each with hundreds of methods so objects suck") or from people
who confuse bad design with a paradigm ("I saw an OOP system that used
every design pattern in the book and it was incomprehensible so
objects suck").
For the more rational, object orientation in Forth serves the same
purpose as object orientation in any other language: It's a way to
factor and organize code and data. In Forth, you have a freedom that
not many languages do-- the freedom to bend and shape objects to fit
whatever notion makes sense to you. If you like prototype-based
object orientation over class-based, you can build that. If you think
multiple inheritance is a good thing, you can build that. If you
favor static early-bound systems over dynamic late-bound systems, you
can build that. And so on. You're not stuck with a singular notion
of what an object is, as in a language like C++. And you're not stuck
with using objects when they don't make sense (like in Java).
Again, you may be more comfortable with a language like Factor than
Forth.
> May I suggest projecteuler.net ? There are far too few Forth
> programmers there. You can start with easy programs, and
> proceed to challenges. Great fun!
>
I will comment on a "thank you" for the tip about projecteuler.net. Yes,
looks like fun. I see that pencil and paper is more popular than Forth in
solving these problems. I'll try my luck with some Forth code as you have
suggested for us newbies. Thanks.
David Johnson
deb...@sdf.lonestar.org
SDF Public Access UNIX System - http://sdf.lonestar.org
Forth is whitebox computing, which is one of its greatest strengths.
Test early and test often.
You should study existing code, especially examples that come with the
commercial Forth evaluation packages. Complex structures and lists can
be built up in the dictionary. WORDLISTs, CREATE and DOES> are very
useful features of Forth which play into the practice of building
structures in the dictionary.
Think of writing nouns and verbs that describe your application
domain. As you browse from the beginning toward the end of your
program, you should see stack noise decreasing and an application-
specific language emerging.
-Brad
Start by writing structs to package your data. Then write a singly-
linked nil-terminated linked-list, which is pretty simple and can take
you a long ways. Think up some cool application to write and only
develop the tools necessary to support that application, rather than
develop complicated tools that you vaguely think might be useful
someday.
On Oct 19, 1:19 am, "Celime" <cm175...@scarlet.be> wrote:
> You may begin with "structures".
> It is a basic abstraction tool.
>
> : +field ( n <"name"> -- ) \ Exec: addr -- 'addr
> create over , + does> @ + ;
I never use DOES> myself, and I don't recommend it to others either.
This is what I would write:
: <field> \ compile-time: offset --
\ run-time: struct-adr -- field-adr
\ stream: name
?dup if : s" literal + ; " evaluate
else : s" ; " evaluate immediate
then ;
: field ( offset size -- new-offset )
\ stream: name
over <field> dup allot
+ ;
\ As a convention, the field names should start with a dot
\ (reminiscent of Pascal fields).
Well, I'd put it slightly differently. OOP can simplify applications
that feature a lot of similar things with varying properties. Some apps
are like that, others are not. OOP carries some overhead, which is
justified it if simplifies your application, but is dead weight in
applications that are strictly procedural in nature.
> Start by writing structs to package your data. Then write a singly-
> linked nil-terminated linked-list, which is pretty simple and can take
> you a long ways. Think up some cool application to write and only
> develop the tools necessary to support that application, rather than
> develop complicated tools that you vaguely think might be useful
> someday.
Good advice.
> On Oct 19, 1:19 am, "Celime" <cm175...@scarlet.be> wrote:
>> You may begin with "structures".
>> It is a basic abstraction tool.
>>
>> : +field ( n <"name"> -- ) \ Exec: addr -- 'addr
>> create over , + does> @ + ;
>
> I never use DOES> myself, and I don't recommend it to others either.
That's a shame. IMO Celime's code is certainly a lot simpler than your
version. Faster, too. What is it about DOES> that you don't like?
Cheers,
Elizabeth
> OOP can simplify applications that feature a lot of similar things
> with varying properties. Some apps are like that, others are not.
And this is the real point of practical programming IMO. Forth almost
forces one to approach problems by asking the question, "what does the
solution *require*", as opposed to the more common HLL approach of, "I
have these particular ways of doing things, how can I solve the
problem with them?".
An example which was recently posted on the Reva forum: someone wanted
to have an 'object' whose instances would do something different each
time they were invoked. To do this, he was going to write some
complex code (far beyond what would be reasonable for this problem).
I suggested a create... does> construct, where the data stored was in
fact the xt to invoke for the action. The does> clause would pass the
pointer to the instance-data to the xt. The invoked action then could
modify the xt to use on the next go-round ... thus implementing a
state-machine (which was really the original goal, restated) without
using if..then or lookup tables (or the needlessly complex code he was
originally going to write).
The point of that exercise was to try to get people to think a bit
differently about how they approach a problem, to get them to see that
they do not have to follow the same paradigms they might use in other
languages, and that ... well, coding Forth is fun!
As someone posted here in c.l.f, you can think about CREATE DOES>
as a tool to define "classes" with a single method (no inheritance,
though)
The words that you define with your "definer word" are the object
instances.
Since all these objects have a single method,
the method name is implicitly known and thus you don't need to write
it.
Greetings
Rafael
That statement works for programmers who find themselves working on
widely-varying kinds of projects in different domains for different
targets. But practically, most programmers are less general in their
work and they face recurring challenges and themes. For example, the
programmer hired to write non-trivial web applications comes out of
the gate with a handful of needs that don't change (maintaining state,
handling authentication, security, database access and mapping,
templating, content and asset management, etc.). These recurring
needs are reflected in web application frameworks which do indeed
impose a certain way to frame solutions. But they arose from
programmers who had to face recurring patterns.
Yes, when one has a hammer, everything looks like a nail. But at the
same time, if you're pounding nails... then a hammer makes perfect
sense and there is no reason to craft a highly specific tool just
because some of the nails are brass and some are aluminum.
Getting back to object orientation, I completely agree that not every
problem screams out for object orientation, just as not every problem
screams out for Forth. Forth's flexibility is no more an excuse for
viewing all solutions through Forth-colored glasses as object
orientation's general applicability to a wide range of problems an
excuse for forcing an OO solution where it isn't necessary.
http://members.shaw.ca/patrickli/resources/Pong2.f
run by typing run-game
I'm starting to get the feel for the concatenative aspect of Forth,
here's some observations:
1) Concatenating words is very elegant ( one can almost think of it as
currying ). Functions are just combinations of other functions.
2) Words with one argument are also very elegant. It reminds me of
dataflow programming where you just follow the data as it "passes
through" functions.
3) However, words with more than one argument are really not very
elegant... two argument words using SWAP and DUP shufflers are still
readable, but as soon as it passes three, the stack noise starts to
become unmanageable, and I see no reason to not use LOCALS at this
point...
To be honest, I can't quite see the advantage of not having named
local variables yet (other than for performance reasons). I would
appreciate an example of an application where it's preferable and
cleaner to avoid named local variables.
Thanks for all your advice. Forth is fun!
-Patrick
>3) However, words with more than one argument are really not very
>elegant... two argument words using SWAP and DUP shufflers are still
>readable, but as soon as it passes three, the stack noise starts to
>become unmanageable, and I see no reason to not use LOCALS at this
>point...
Having a lot of data makes life difficult in Forth. Good engineers
are lazy, and make life easy for themselves. They just factor the
problem into smaller words with fewer parameters. A result of this
is that good Forth has a large number of very small components.
This in turn promotes code reuse at a very fine grain - no "call
by text editor", and reduces code size.
A side effect of rigourous factoring is that, providing the external
effect of a word is maintained, it can be completely rewritten to
use a different storage mechanism, comms channel and so on. This
makes Forth code very malleable. Yes, you can write C in Forth, but
the C programming culture doesn't promote it.
>To be honest, I can't quite see the advantage of not having named
>local variables yet (other than for performance reasons). I would
>appreciate an example of an application where it's preferable and
>cleaner to avoid named local variables.
We don't teach local variables early on in Forth life because we
know from experience that a proportion of people familiar with
Pasgol languages will latch on to them and just ignore the stack.
Nearly all modern Forths support local variables using either the
ANS
locals| ... |
or the more modern Forth200x
{ ... }
notation. Where a system provides both, the majority of users
prefer the brace notation.
My personal observation is that, except for OS interfacing, code
that uses a large number of input parameters is usually taking
them from one or two structures. I thus prefer to pass the address
of the structure around.
Stephen
--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads
Some of my functions that are entered with three or four items on the
stack don't use SWAP at all. If the arguments are supplied in the order
needed, DUP and OVER suffice.
Jerry
--
Engineering is the art of making what you want from things you can get.
�����������������������������������������������������������������������
> For example, the programmer hired to write non-trivial web applications
> comes out of the gate with a handful of needs that don't change (maintaining
> state ...
> Yes, when one has a hammer, everything looks like a nail. But at the
> same time, if you're pounding nails... then a hammer makes perfect
> sense and there is no reason to craft a highly specific tool just
> because some of the nails are brass and some are aluminum.
Can't disagree with that. My personal work experience has involved a
very
wide variety of problem domains, so I've had to have a very flexible
toolbox.
But certainly, when I write an application server I appreciate e.g.
Java and
its associated frameworks etc.
Indeed. You can also think of words as always taking one argument (a
stack) and returning one argument (a stack).
Also, I think Forthers tend to think in phrases which preserve stack
depth. For example, (2 + 3) * 4 is chunked into: 2, 3 +, 4 *.
This shows up in the names of abbreviations like "1+" and "2/".
> 3) However, words with more than one argument are really not very
> elegant... two argument words using SWAP and DUP shufflers are still
> readable, but as soon as it passes three, the stack noise starts to
> become unmanageable, and I see no reason to not use LOCALS at this
> point...
>
> To be honest, I can't quite see the advantage of not having named
> local variables yet (other than for performance reasons). I would
> appreciate an example of an application where it's preferable and
> cleaner to avoid named local variables.
I tend to think of it like pronouns in natural language. If you you
have few objects/subjects reused often, use the pronoun (DUP, OVER,
2DUP). If you have many objects which are used simultaneously, use
locals. If some of those objects are used globally or modified
infrequently, make them values/variables.
What Forth realizes is that like natural language, concepts can
frequently be broken down so there is only one object and/or one
subject, in which case anonymous pronouns are more succinct.
> Thanks for all your advice. Forth is fun!
> -Patrick
Your code looks very clean! A few suggestions:
40 constant width
20 constant height
3 constant init-x \ and also use these in your reset words
7 constant init-y
: create-paddle ( down up y x -- ) create , , , , ;
char s char w init-y init-x create-paddle p1
char l char o init-y width init-x - create-paddle p2
I don't recognize "wipe", but there is a standard word "page" for
clearing the screen.
"negate" is a synonym for "-1 *":
: reverse ( speed -- ) dup @ negate swap ! ; \ ball-speed .x
reverse
Maybe use "within" for range checks.
You might try "2@" instead of the pattern "dup .x @ swap .y @", and
"2!" for ".xy!"
The abbreviation for "paddle .y @ + paddle .y !" is "paddle .y
+!" (Some Forths also have "+TO" which does the same thing with
values.)
Seems to me that next-key should remain a parameter:
: update-paddle ( key paddle -- key )
2dup .up @ = if
-1 over .y +! \ or keep : move-paddle ( inc paddle ) .y
+! ;
else 2dup .down @ = if
1 over .y +!
then then drop ;
...
key
p1 update-paddle
p2 update-paddle
drop
"begin true while ... repeat" is the same as "begin ... again"
(My own first toy problem was porting the TSCP chess program. I also
have been having fun implementing the Rosetta Code problems at
http://www.rosettacode.org/)
Keep on having fun!
Ian
The locals were not there because one had to implement them first, and
Mr Moore used the stack instead. The problem with locals is that their
lifetime/scope needs to span about a page of text, while a function
typically is one line (7 words average). In many cases a human can
think out a workaround, including the right order of values (which is
_very_ important). I typically extend the number of items that may be
used by using the return stack and defining
: PLUCK 2 PICK ; ( a b c -- a b c a )
\ equivalent to 2R@ DROP, the 2nd element at the return stack
: R'@ R> 2R@ DROP SWAP >R ; ( r: a b -- a b ) ( -- a )
and even
R"@ ( r: a b c -- a b c ) ( -- a )
The problem with locals is that in their presence definitions grow to
include the whole desired scope/lifetime, which undermines the fine-
grained modularity. At second, they are compile-only, which once more
undermines command-line testing. So you begin with locals and end with
a C-like language that uses reversal Lookasievich (Lukasievicz)
notation and whose phrases cannot be tested in command line. You try
to compensate one weakness and lose the strength of immunity to other
weaknesses.
In programming languages in general, there is a notion of _activation
record_, that contains parameters passed to a function. When an Algol
calls a function, it creates an activation record, and destroys it
when the function returns. What is important for us is the parallel
between function invocation and records. And one more considerations:
data often form a set and get passed together to a number of different
functions calling each other. That is, it may be meaningful to reuse
at least the structure of an activation record in many functions. Or
just use the same activation record.
\ Structures
\ I prefer accessor functions to offsets
: sfield create dup , does> @ + ;
: sfield@ create dup , does> @ + @ ;
: sfield! create dup , does> @ + ! ;
0
sfield@ x sfield! x! CELL+
sfield@ y sfield! y! CELL+
constant /2dpoint
/2dpoint
sfield@ z sfield! z! CELL+
constant /3dpoint
create mypoint /3dpoint allot
10 mypoint x!
20 mypoint y!
30 mypoint z!
mypoint x . mypoint y . mypoint z .
10 20 30 ok
\ Array indexing
: [] swap cells + @ ;
: []! swap cells + ! ;
: []^ swap cells + ;
: ][ cells + @ ;
: ][! cells + ! ;
: ][^ cells + ;
create myarray 100 , 200 , 300 ,
myarray 2 ][ . \ 300
1 myarray [] . \ 200
\ variables whose scope is a screen
: arg create dup , does> @ here + @ ;
: arg! create dup , does> @ here + ! ;
: cell- 1 cells - ;
0
cell- arg xx arg! xx!
cell- arg yy arg! yy!
negate constant /my2args
/my2args negate
cell- arg zz arg! zz!
negate constant /my3args
: mk-my3args ( x y z -- ) /my3args allot zz! yy! xx! ;
: rm-my3args ( -- ) /my3args negate allot ;
\ visible to functions:
: all. xx . yy . zz . ;
\ usable in command line:
here .
111 222 333 mk-my3args
all.
rm-my3args
here .
here . 140594645728440 ok
111 222 333 mk-my3args ok
all. 111 222 333 ok
rm-my3args ok
here . 140594645728440 ok
With this package, you can use locals only to replace ugly stack
manipulations and avoid using locals as a means of passing data
between program modules. (The smallest module in C is 1-3 lines of
code that have a separate meaning. You must avoid such modules in
Forth, that is, such modules must become functions.)
> \ I prefer accessor functions to offsets
> : sfield create dup , does> @ + ;
> : sfield@ create dup , does> @ + @ ;
> : sfield! create dup , does> @ + ! ;
This requires _3_(!!) words for each field type.
Having separate getter and setter means that you rule out in-place
operations, which leads to loss of efficiency.
> \ Array indexing
> : [] swap cells + @ ;
> : []! swap cells + ! ;
> : []^ swap cells + ;
Again two extra words because you enforce getter and setter instead
of using raw access to array element.
> : ][ cells + @ ;
> : ][! cells + ! ;
> : ][^ cells + ;
Same.
This isn't "1x programming", this is thrice as much as equivalent Forth code.
--
HE CE3OH...
Where do you see _3_ words for each field type?
0
sfield@ x sfield! x! CELL+
sfield@ y sfield! y! CELL+
constant /2dpoint
/2dpoint
sfield@ z sfield! z! CELL+
constant /3dpoint
: sfieldc@ create dup , does> @ + c@ ;
: sfieldc! create dup , does> @ + c! ;
/3dpoint
sfieldc@ t-len sfieldc! t-len! char+
sfield t 80 chars +
aligned
constant /commented(OMG!)3DPoint
>
> > \ Array indexing
> > : [] swap cells + @ ;
> > : []! swap cells + ! ;
> > : []^ swap cells + ;
>
> Again two extra words because you enforce getter and setter instead
> of using raw access to array element.
>
> > : ][ cells + @ ;
> > : ][! cells + ! ;
> > : ][^ cells + ;
>
> Same.
>
> This isn't "1x programming", this is thrice as much as equivalent Forth code.
The motivation for getters and setters is the same as behind the use
of named constants rather than numeric constants in the code. I do not
want the algorithm to include information about the size of structure
fields. I have written an amount of code that should work on a
resource-constrained embedded system but could then be ported to a
desktop (and vice versa). I used 1-byte integers on the embedded
system and 32-bit integers on the desktop. Therefore I avoided the use
of words that imply knowledge of field sizes and used structures as an
opaque type. Getters and setters provide a uniform access for fields
of whatever size.
Another example of the same sort could be a network protocol on two
targets, 16-bit and 32-bit. A 32-bit value would be double or single
depending on the platform. (OTOH, in this particular case one can use
16@ and 32@ instead of @ and 2@, because the size of packet fields is
not going to change, in contrast to the above case.)
At second, I consider all these separate @ and ! as stack noise. The
same as VALUE vs VARIABLE.
Other people in c.l.f. reported that they never change the size of
structure fields. I think, it also implies that they do not bother
about the @ stack noise.
> On Oct 22, 5:33О©╫am, Aleksej Saushev <a...@inbox.ru> wrote:
>> m_l_g3 <m_l...@yahoo.com> writes:
>> > \ I prefer accessor functions to offsets
>> > : sfield create dup , does> @ + ;
>> > : sfield@ create dup , does> @ + @ ;
>> > : sfield! create dup , does> @ + ! ;
>>
>> This requires _3_(!!) words for each field type.
>> Having separate getter and setter means that you rule out in-place
>> operations, which leads to loss of efficiency.
>
> Where do you see _3_ words for each field type?
See above. "sfield", "sfield@" and "sfield!" make 3 words per field type.
> 0
> sfield@ x sfield! x! CELL+
> sfield@ y sfield! y! CELL+
> constant /2dpoint
Even Gforth provides saner notation than yours:
struct cell% field .x cell% field .y end-struct 2d-point%
And then I use regular @ and ! to access record fields.
> /2dpoint
> sfield@ z sfield! z! CELL+
> constant /3dpoint
2d-point% cell% field .z end-struct 3d-point%
Still shorter and less noisy.
> : sfieldc@ create dup , does> @ + c@ ;
> : sfieldc! create dup , does> @ + c! ;
>
> /3dpoint
> sfieldc@ t-len sfieldc! t-len! char+
> sfield t 80 chars +
> aligned
> constant /commented(OMG!)3DPoint
3d-point%
cell% field .comment-len char% 80 * field .comment
( aligned automatically )
end-struct commented-3d-point%
>> > \ Array indexing
>> > : [] swap cells + @ ;
>> > : []! swap cells + ! ;
>> > : []^ swap cells + ;
>>
>> Again two extra words because you enforce getter and setter instead
>> of using raw access to array element.
>>
>> > : ][ cells + @ ;
>> > : ][! cells + ! ;
>> > : ][^ cells + ;
>>
>> Same.
>>
>> This isn't "1x programming", this is thrice as much as equivalent Forth code.
>
> The motivation for getters and setters is the same as behind the use
> of named constants rather than numeric constants in the code. I do not
> want the algorithm to include information about the size of structure
> fields. I have written an amount of code that should work on a
> resource-constrained embedded system but could then be ported to a
> desktop (and vice versa). I used 1-byte integers on the embedded
> system and 32-bit integers on the desktop. Therefore I avoided the use
> of words that imply knowledge of field sizes and used structures as an
> opaque type. Getters and setters provide a uniform access for fields
> of whatever size.
Thus one concludes that Forth stuck to late 60s or early 70s,
when they didn't decide where to store size information, in type
or in explicit constants.
You still need size information even with your getters and setters.
Consider what happens if getter fetches 2 cells instead of one,
and you need to process it somehow rather than simply moving from one
place to another.
> Another example of the same sort could be a network protocol on two
> targets, 16-bit and 32-bit. A 32-bit value would be double or single
> depending on the platform. (OTOH, in this particular case one can use
> 16@ and 32@ instead of @ and 2@, because the size of packet fields is
> not going to change, in contrast to the above case.)
That's why we have "uint32_t" rather than "u_long" or some other integer
type of unknown range.
> At second, I consider all these separate @ and ! as stack noise. The
> same as VALUE vs VARIABLE.
>
> Other people in c.l.f. reported that they never change the size of
> structure fields. I think, it also implies that they do not bother
> about the @ stack noise.
This points to intrinsic problems in Forth rather than lack of need.
--
HE CE3OH...
You don't really like Forth do you? I wonder why you bother.
> http://members.shaw.ca/patrickli/resources/Pong2.f
> run by typing run-game
> I'm starting to get the feel for the concatenative aspect of Forth,
> here's some observations:
> 1) Concatenating words is very elegant ( one can almost think of it as
> currying ). Functions are just combinations of other functions.
> 2) Words with one argument are also very elegant. It reminds me of
> dataflow programming where you just follow the data as it "passes
> through" functions.
> 3) However, words with more than one argument are really not very
> elegant... two argument words using SWAP and DUP shufflers are still
> readable, but as soon as it passes three, the stack noise starts to
> become unmanageable, and I see no reason to not use LOCALS at this
> point...
As soon as the number of args passes three, you're (probably) doing
something wrong. There are two things you can do at this point: patch
things up using locals or change the way your code is factored. The
latter is almost always better, and it's the reason most people
teaching Forth don't introduce locals at the beginning.
> To be honest, I can't quite see the advantage of not having named
> local variables yet (other than for performance reasons). I would
> appreciate an example of an application where it's preferable and
> cleaner to avoid named local variables.
This is a very controversial topic on comp.lang.forth.
Last year we had a long argument about stack handling and elegant
code. There's a classic problem (from _Thinking FORTH_) about how to
draw a box, given a primitive called LINE that takes ( x y x' y').
This takes four arguments, and without locals the result is tragic.
(Try it if you're feeling masochistic!)
Using locals makes it tolerable:
> : BOX2 { l t r b -- }
> l t r t LINE
> r t r b LINE
> r b l b LINE
> l b l t LINE ;
The key to improvins the situation is to have a current cursor
position and redefine DRAW so that it takes only a single (y x) pair
and draws from the current position to (y x), and a word AT which sets
the current position:
> : DRAW-BOX ( top left bottom right)
> 2OVER AT
> ROT >R >R
> OVER R@ DRAW
> DUP R> DRAW
> R@ DRAW
> R> DRAW ;
or
>: DRAW-BOX ( top left bottom right)
> 2OVER OVER SWAP AT
> OVER DRAW OVER SWAP DRAW
> OVER DRAW DRAW ;
(Note that DRAW sets the current position to the end of the line once
it's done.)
Nicer, but still a lot of stack juggling. Extend this idea a bit
more, and you can define a few words that make things easier. For
example, if you have words @X and @Y that return the current X and Y
position, then
: >X ( x - y x) @Y SWAP ;
: >Y ( y - y x) @X ;
: DRAW-BOX ( top left bottom right)
2OVER AT >X DRAW >Y DRAW >X DRAW >Y DRAW ;
Andrew.
>> This points to intrinsic problems in Forth rather than lack of need.
>>
> You don't really like Forth do you? I wonder why you bother.
You're fool, aren't you?
If I cared nothing, I wouldn't bother writing. So, please, in future
either bother learning anything or stay away with your foolish comments.
Otherwise any reasonable person will laugh at your "you don't need to
eat today" opinions.
In particular, the problem above is of bounded mind: "I don't do it,
thus it isn't needed. I can't imagine it, thus it is impossible."
--
HE CE3OH...
> CuppoJava <patrick...@hotmail.com> wrote:
>> Following Michael's suggestion, I wrote a small text-based PONG game
>> to get acquainted with Forth.
>
>> http://members.shaw.ca/patrickli/resources/Pong2.f
>> run by typing run-game
>
>> I'm starting to get the feel for the concatenative aspect of Forth,
>> here's some observations:
>> 1) Concatenating words is very elegant ( one can almost think of it as
>> currying ). Functions are just combinations of other functions.
>> 2) Words with one argument are also very elegant. It reminds me of
>> dataflow programming where you just follow the data as it "passes
>> through" functions.
>> 3) However, words with more than one argument are really not very
>> elegant... two argument words using SWAP and DUP shufflers are still
>> readable, but as soon as it passes three, the stack noise starts to
>> become unmanageable, and I see no reason to not use LOCALS at this
>> point...
>
> As soon as the number of args passes three, you're (probably) doing
> something wrong.
Why? Now let's listen to your arguments.
I wonder, if they differ a little from what those old farts tell.
> There are two things you can do at this point: patch
> things up using locals or change the way your code is factored. The
> latter is almost always better, and it's the reason most people
> teaching Forth don't introduce locals at the beginning.
Try proving it.
>> To be honest, I can't quite see the advantage of not having named
>> local variables yet (other than for performance reasons). I would
>> appreciate an example of an application where it's preferable and
>> cleaner to avoid named local variables.
>
> This is a very controversial topic on comp.lang.forth.
>
> Last year we had a long argument about stack handling and elegant
> code. There's a classic problem (from _Thinking FORTH_) about how to
> draw a box, given a primitive called LINE that takes ( x y x' y').
> This takes four arguments, and without locals the result is tragic.
> (Try it if you're feeling masochistic!)
"Thinking Forth" is obsolete, many opinions it promotes were proved
wrong in recent 20 years.
> Using locals makes it tolerable:
>
>> : BOX2 { l t r b -- }
>> l t r t LINE
>> r t r b LINE
>> r b l b LINE
>> l b l t LINE ;
>
> The key to improvins the situation is to have a current cursor
> position and redefine DRAW so that it takes only a single (y x) pair
> and draws from the current position to (y x), and a word AT which sets
> the current position:
This introduces global state, which is more evil than using locals.
In particular, this is one of reasons, why Forth code sucks so much,
pretty any non-trivial Forth code isn't reentrable, it is almost sure bet.
--
HE CE3OH...
> > Using locals makes it tolerable:
> >
> >> : BOX2 { l t r b -- }
> >> l t r t LINE
> >> r t r b LINE
> >> r b l b LINE
> >> l b l t LINE ;
> >
> > The key to improvins the situation is to have a current cursor
> > position and redefine DRAW so that it takes only a single (y x) pair
> > and draws from the current position to (y x), and a word AT which sets
> > the current position:
> This introduces global state, which is more evil than using locals.
No, that's wrong: the current cursor position is associated with the
device on which you're drawing the line. The state of that device
includes everything you've drawn on it and its cursor.
If this device is to be concurrently shared with other tasks, then the
current cursor position has to be in a USER variable, one that's local
to the task that's doing the drawing. But IME it's more common (and
probably better design) to have a single task handling the device,
taking requests from a queue.
Andrew.
It isn't about parallel execution _only_. It is about subroutine calls as well.
Here using global state may violate reference transparency, In turtle graphics
it leads to the necessity of maintaining strict state save-restore protocol,
otherwise you cannot call other words that draw anything. How can you be sure
that their path is closed? Do you require all words that use drawing primitives
to restore the state? You didn't even think about it, did you? Otherwise you'd
have mentioned that you don't need to save and restore cursor, since you return
to the starting point. You're lucky because you've choosen quite forgiving task
for your demonstration, and I've lost such good chance to put you into mess,
because I should've asked you to draw, for instance, a rectangular wave (pulse)
before mentioning problems with global state.
--
HE CE3OH...
This is absurd. Referential transparency is impossible because DRAW
has a side-effect: it draws a line on the device.
> In turtle graphics it leads to the necessity of maintaining strict
> state save-restore protocol, otherwise you cannot call other words
> that draw anything. How can you be sure that their path is closed?
> Do you require all words that use drawing primitives to restore the
> state?
This isn't turtle graphics. When you need to move to a particular
position, use AT.
Andrew.
Apparently, you aren't getting turtle graphics at all. Try for an exercise
drawing fractal curves with turtle graphics: The manipulation of the current
cursor position is part of the exercise. The turtle graphics with its
global state is equivalent to the L system describing these curves.
Save/restore commands certainly are useful in Turtle graphics, but not, as
you argue, strictly necessary. Original Logo turtle graphics certainly
lacked it.
--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/
> Aleksej Saushev wrote:
>> It isn't about parallel execution _only_. It is about subroutine calls as
>> well. Here using global state may violate reference transparency, In
>> turtle graphics it leads to the necessity of maintaining strict state
>> save-restore protocol, otherwise you cannot call other words that draw
>> anything.
>
> Apparently, you aren't getting turtle graphics at all. Try for an exercise
> drawing fractal curves with turtle graphics: The manipulation of the current
> cursor position is part of the exercise. The turtle graphics with its
> global state is equivalent to the L system describing these curves.
>
> Save/restore commands certainly are useful in Turtle graphics, but not, as
> you argue, strictly necessary. Original Logo turtle graphics certainly
> lacked it.
Fractals are quite another problem. You don't draw fractals every day,
but you do call subroutines every day, only... Not in Forth.
--
HE CE3OH...
> Aleksej Saushev <as...@inbox.ru> wrote:
>> In turtle graphics it leads to the necessity of maintaining strict
>> state save-restore protocol, otherwise you cannot call other words
>> that draw anything. How can you be sure that their path is closed?
>> Do you require all words that use drawing primitives to restore the
>> state?
>
> This isn't turtle graphics. When you need to move to a particular
> position, use AT.
What should I do if I want to _stay_ in the very position, when I gave
control to subroutine? Poll state, save it manually and then "AT"?
Anyway, that you insist that this kind factoring is good, means that you
have very little experience solving complex tasks in Forth. Because this
global state usage is one of reasons why you cannot use e.g. FSL even
for academic tasks. Not out of the box and only after much time investment.
--
HE CE3OH...
> > Aleksej Saushev <as...@inbox.ru> wrote:
> >> In turtle graphics it leads to the necessity of maintaining strict
> >> state save-restore protocol, otherwise you cannot call other words
> >> that draw anything. How can you be sure that their path is closed?
> >> Do you require all words that use drawing primitives to restore the
> >> state?
> >
> > This isn't turtle graphics. When you need to move to a particular
> > position, use AT.
> What should I do if I want to _stay_ in the very position, when I
> gave control to subroutine? Poll state, save it manually and then
> "AT"?
That depends. If you moved somewhere during of a word, then you know
where you moved to, so you can go back there. If you didn't, then the
initial cursor position can be saved then restored. Effectively, the
cursor position is passed to the word as an initial argument.
> Anyway, that you insist that this kind factoring is good, means that
> you have very little experience solving complex tasks in Forth.
I guess so.
Andrew.
Postscript has a current point, like you propose, and does not have
turtle graphics. It has gsave and grestore for saving and restoring
the graphics state (including the current point), and these operators
are used quite a lot in my Postscript code as well as the Postscript
code of others that I have seen.
- 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: http://www.forth200x.org/forth200x.html
EuroForth 2009: http://www.euroforth.org/ef09/
So does Windows (GDI). It has a 'current point' (set using MoveToEx)
and functions to save and restore the graphics state (SaveDC,
RestoreDC). IME that's an extremely common paradigm for drawing
graphics.
BB4Wforth works the same way, because its graphics words use BBC
BASIC's drivers, and all Acorn platforms have the concept of 'current
point'.
Richard.
http://www.rtrussell.co.uk/
To reply by email change 'news' to my forename.
Yes, with cursor-relative drawing the drawing resource can have
sharing issues, like when multiple tasks send strings out a serial
port. Probably not a good idea to just let them spew bytes. Display
state can be part of a structure pointed to by a single variable.
Whoever writes to the display must own the structure. The pointer can
be stored on the stack, changed for drawing and then restored. Kind of
like Windows but without all the obfuscation. But it would cleaner to
just avoid global state.
What do you suggest for scoping locals over a module? I think frame
setup and teardown functions would be needed, but I haven't thought of
a syntax that's enforceable by the compiler.
-Brad
> Aleksej Saushev <as...@inbox.ru> wrote:
>> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>
>> > Aleksej Saushev <as...@inbox.ru> wrote:
>> >> In turtle graphics it leads to the necessity of maintaining strict
>> >> state save-restore protocol, otherwise you cannot call other words
>> >> that draw anything. How can you be sure that their path is closed?
>> >> Do you require all words that use drawing primitives to restore the
>> >> state?
>> >
>> > This isn't turtle graphics. When you need to move to a particular
>> > position, use AT.
>
>> What should I do if I want to _stay_ in the very position, when I
>> gave control to subroutine? Poll state, save it manually and then
>> "AT"?
>
> That depends. If you moved somewhere during of a word, then you know
> where you moved to, so you can go back there. If you didn't, then the
> initial cursor position can be saved then restored. Effectively, the
> cursor position is passed to the word as an initial argument.
But you agree that you have to maintain some protocol on current point
usage, don't you?
This part isn't even considered by Forth advocates when they talk about
this rectangle example. And this is what effectively invalidates it,
because solutions are not equivalent any more: when you have "draw line
between given points" primitive, you can reorder them and parallelize
(to some extent), you don't need to maintain state across subroutine calls,
and when you introduce state, you have to consider how its very existence
affects other operations.
The latter part doesn't get _any_ attention, though it is very important.
When you draw rectangle by given center position and dimensions, who is
to restore the state? Caller? Callee? How does this change your
demonstration code?
Throw-away code may be any, demonstration code is not allowed to.
This classic rectangle example as it is usually present is about
throw-away code. It doesn't show how it plays along with other code.
Thus it isn't demonstrative at the very least.
--
HE CE3OH...
This is an application design issue. I have worked with a great many
graphics devices in Forth, from the mid-70's to the mid-90's, both
vector and raster graphics devices. FORTH, Inc. has supported complete
graphics packages for many such devices.
IMO considering and maintaining the state of the device you're
controlling is essential. The device *has* a state: a current cursor
position in x,y, a beam condition (on or off), perhaps a current color
and other features, and maybe even existing information on the screen. A
graphics package, to be useful, needs to manage this state, potentially
in world coordinates as well as screen coordinates.
As Andrew mentioned, the simplest design practice is to have a single
task responsible for the graphics device. In applications I've worked
on where multiple tasks needed to update a screen (e.g. a real-time
monitor) they were assigned different regions to manage, and each had
its own "current position" and other parameters that are local to the task.
> When you draw rectangle by given center position and dimensions, who is
> to restore the state? Caller? Callee? How does this change your
> demonstration code?
I would never draw a rectangle that way. Asking for trouble.
> Throw-away code may be any, demonstration code is not allowed to.
> This classic rectangle example as it is usually present is about
> throw-away code. It doesn't show how it plays along with other code.
> Thus it isn't demonstrative at the very least.
Andrew (who has worked with FORTH, Inc. graphics packages) was
attempting to give a realistic example. It's hard to extract real-world
code for an example in a newsgroup; his inclusion of the concept of
cursor position reflects a real-world issue that a real graphics package
would need to deal with.
Cheers,
Elizabeth
--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com
"Forth-based products and Services for real-time
applications since 1973."
==================================================
> > Aleksej Saushev <as...@inbox.ru> wrote:
> >> Andrew Haley <andr...@littlepinkcloud.invalid> writes:
> >
> >> > Aleksej Saushev <as...@inbox.ru> wrote:
> >> >> In turtle graphics it leads to the necessity of maintaining strict
> >> >> state save-restore protocol, otherwise you cannot call other words
> >> >> that draw anything. How can you be sure that their path is closed?
> >> >> Do you require all words that use drawing primitives to restore the
> >> >> state?
> >> >
> >> > This isn't turtle graphics. When you need to move to a particular
> >> > position, use AT.
> >
> >> What should I do if I want to _stay_ in the very position, when I
> >> gave control to subroutine? Poll state, save it manually and then
> >> "AT"?
> >
> > That depends. If you moved somewhere during of a word, then you know
> > where you moved to, so you can go back there. If you didn't, then the
> > initial cursor position can be saved then restored. Effectively, the
> > cursor position is passed to the word as an initial argument.
> But you agree that you have to maintain some protocol on current point
> usage, don't you?
> This part isn't even considered by Forth advocates when they talk
> about this rectangle example.
I'm not surprised, because it's irrelevant to the example.
> And this is what effectively invalidates it, because solutions are
> not equivalent any more: when you have "draw line between given
> points" primitive, you can reorder them and parallelize (to some
> extent), you don't need to maintain state across subroutine calls,
It wouldn't be difficult to do that. If you really wanted to
parallellize this, you'd introduce a queue of operations, and each
element in the queue would have the starting position attached to it.
But the fact of parallel implementation shouldn't leak out into the
API that the programmer sees.
> and when you introduce state, you have to consider how its very
> existence affects other operations.
Well, obviously. The whole point of maintaining the state is its
effect on other operations.
> The latter part doesn't get _any_ attention, though it is very
important.
> When you draw rectangle by given center position and dimensions, who
> is to restore the state? Caller? Callee?
You probably don't need to restore the state. Only the caller knows
that. There's no point in saving and restoring something that won't
be used.
> How does this change your demonstration code?
Given a different job to do, the word would be different. Obviously.
Andrew.
Well, of course you have to. But what kind of protocol you want to
depends on the task you are doing. E.g. if you want to draw text
character by character, the probably nicest way to do it is to advance
the cursor just by the size of the character (that's how terminals
work). If you want to draw text line by line, the subroutine drawing a
single line should advance the cursor by one line. If you are drawing a
fractal, the recursive invocation should advance by one unit. Drawing
trees certainly should leave the state as called.
PostScript and similar systems with a more complex current state also
have transformations (a complete matrix, allowing not only transposing
drawn elements, but also scale them, rotate them, and so on), where the
usual idea is that a subroutine should not leave this state in something
unexpected by the caller. I.e. the general rule for such a subroutine
is to document all the side effects.
The global state helps a lot to write these drawing functions. Through
the global state, all functions are position invariant (i.e. when you
transpose the whole page, all elements inside are transposed as well).
They are invariant to all kinds of operations you can perform to the
current state - you can rotate whole pages, you can mirror them, scale
them, and so on. This is a huge advantage over the system you propose,
and what e.g. X lib has, where all operations have absolute coordinates,
and there's no current state.
Some of these systems got the current state somehow wrong, e.g. OpenGL.
OpenGL's current state works nicely if you have complete objects in 3D
coordinates to paint - they are all invariant to all the operations you
can do on the global state (translate them, rotate them, scale them,
shear them, perform whatever linear operation you can imagine).
However: if you haven't, and want to construct them e.g. through
defining section planes, it doesn't work. Therefore, my 3D turtle
graphics has to introduce again another global state, and leave OpenGL's
global state in the default setting.
OpenGL got other things wrong, as well, that's why OpenGL 3.0 tries to
change the whole interface to one with less abstraction and easier to
optimize on the actual hardware (you transmit points in one array, and
which points to use in the mesh in another array, avoiding double
transformations on points used more than once - and in a triangle mesh,
all points are used several times).
I am curious about applications for the internet and clustering liek
forth-linda where you can take multiple cheap hardware nodes and
create an app that won't stop if some fo the nodes fail. Things like
web DNS authentication database servers that can be used for large
scale. Things liek storage devices and array management done in forth
in less memory and with more efficiency than c. Things that go head
to head with other languages and win in efficiency. Those kinds of
apps would show that forth can compete with c or ruby or lisp and
win.
Is writing such lists and structs covered in thnking forth?
If not where can one learn them?
As you may have gathered from the other responses, locals
in forth are generally frowned upon - not least because forth's
inventor is adamant locals are unnecessary and a mistake.
Not all forths support locals. Locals are an ANS option
and even ANS was ambivalent about supplying them (A.13).
AFAIK few, if any, target compilers for embedded apps
provide locals.
Back to your program. I note there was no attempt to use
the return stack for holding temps. For comparison purposes
here are the same definitions but without locals ...
: in-paddle-y ( y paddle )
swap >r
paddle-range ( lo hi )
r@ > swap r> <= and ;
: in-paddle ( x y paddle) dup >r
in-paddle-y swap r> in-paddle-x and ;
: .xy! tuck .y ! .x ! ;
: move-paddle ( inc paddle ) .y +! ;
: update-paddle >r
next-key r@ .up @ = if
-1 r@ move-paddle
else next-key r@ .down @ = if
1 r@ move-paddle
then then r> drop ;
\ or
0 value paddle \ a 'local' global
: update-paddle to paddle
next-key paddle .up @ = if
-1 paddle move-paddle
else next-key paddle .down @ = if
1 paddle move-paddle
then then ;
For structs, the place to start is the proposal accepted for
Forth 200x:
http://www.forth200x.org/structures.html
That and a bit more are here:
http://www-personal.umich.edu/~williams/archive/forth/utilities/#structs
For lists, my library attempts to be reasonably comprehensive
and documented:
http://www-personal.umich.edu/~williams/archive/forth/lists/
-- David
>Not all forths support locals. Locals are an ANS option
>and even ANS was ambivalent about supplying them (A.13).
>AFAIK few, if any, target compilers for embedded apps
>provide locals.
The MPE VFX cross compilers have supported both types of locals
for many years.
locals| ... |
and
{ ... | ... -- ... }
We also support local buffers.
Stephen
--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads
I did attempt to verify my assertion. Forth Inc's cross-compiler
manuals don't mention locals (can't say I've actually tried it ).
Browsing the MPE website cross-compiler page made no specific
reference to locals so I couldn't be sure. I don't know what other
forth vendors (are there any?) may have.
From my observation it is the amateur forth implementers that
are the greatest proponents of locals in forth. Whenever the
topic of "are locals evil" arises on c.l.f., both Forth Inc and MPE
reps appear to downplay - if not discourage - their use. Some
of your comments on the performance cost of locals have
sounded positively damning. If correct, one would assume
embedded apps with limited resources/cpu capacity would be
the last place one would choose to use locals.
Most embedded system applications don't require hi-level language
constructs. It's mostly those who want to program in Forth on a fat PC
for whatever reason.
Andreas
> Aleksej Saushev wrote:
>> But you agree that you have to maintain some protocol on current point
>> usage, don't you?
>
> Well, of course you have to.
So, do you agree, that that drawing rectangle example should consider
consequences of global state introduction? At least the basic ones.
It's nice that you recall practical examples when global state comes
with (sometimes high) price. Why isn't this discussed along with drawing
rectangle example?
Many people consider this desceptive, and it is desception, because
Forth advocates silently skip all problems that arise from the
demonstrated approach. Of course, newbies don't understand it first,
but they're not all idiots. When they find it out later, they make
corresponding opinion on Forth.
--
HE CE3OH...
>Whenever the
>topic of "are locals evil" arises on c.l.f., both Forth Inc and MPE
>reps appear to downplay - if not discourage - their use. Some
>of your comments on the performance cost of locals have
>sounded positively damning. If correct, one would assume
>embedded apps with limited resources/cpu capacity would be
>the last place one would choose to use locals.
Our client base has very little in common with c.l.f.
We provide tools for Forth programmers. We can advise best
practise, but we certainly cannot constrain people who wish
to use certain techniques and may have good reasons for
doing so.
Yes, there's usually a performance penalty for using locals,
but that's a quality of implementation issue if there are
enough registers, and you can accept the compiler complexity.
In a cross compiler, providing locals takes resources on
the host, but if unused takes no resources on the target.
Personally, I would avoid locals on 8 bit CPUs, could
accept them on modern 16 bit CPUs, and have used them on
32 bit CPUs. Locals are valuable to permit thread and
interrupt safe words with lower overall RAM consumption than
USER variables. In single-chip 32 bit applications RAM is a
much scarcer resource than Flash.
> It's nice that you recall practical examples when global state comes
> with (sometimes high) price.
This is a bizarre misinterpretation of what Bernd said, which was that
a system with global state has a "huge advantage over the system you
propose". He said that some systems, for example OpenGL, get this
wrong, but so what? It's possible to get things wrong.
> Why isn't this discussed along with drawing rectangle example?
Because it's irrelevant to this simple example.
> Many people consider this desceptive,
Many people? This is a feeble attempt at argumentum ad numerum.
You're trying to bolster your argument with a vision of imaginary
crowds.
> and it is desception, because Forth advocates silently skip all
> problems that arise from the demonstrated approach.
Nonsense. You're trying to hijack a simple discussion about Forth
design by nitpicking.
Andrew.
> Aleksej Saushev <as...@inbox.ru> wrote:
>
>> It's nice that you recall practical examples when global state comes
>> with (sometimes high) price.
>
> This is a bizarre misinterpretation of what Bernd said, which was that
> a system with global state has a "huge advantage over the system you
> propose". He said that some systems, for example OpenGL, get this
> wrong, but so what? It's possible to get things wrong.
Bernd said the very thing I'm trying to get into your head: that you
_have_ to maintain global state, if you've got one.
>> Why isn't this discussed along with drawing rectangle example?
>
> Because it's irrelevant to this simple example.
It is relevant to this very example, because it introduces global state
where there wasn't any before.
>> Many people consider this desceptive,
>
> Many people? This is a feeble attempt at argumentum ad numerum.
> You're trying to bolster your argument with a vision of imaginary
> crowds.
I'm talking about real people. I don't imagine problems, there're more
than enough already. It's just you trying hard not to notice them.
If there're no problems with Forth and it is easy to use, where's the
open source software other than toy interpreters? You cannot answer any
question of this kind, because almost anything is much harder to write
in Forth, and you don't even understand why it is so.
>> and it is desception, because Forth advocates silently skip all
>> problems that arise from the demonstrated approach.
>
> Nonsense. You're trying to hijack a simple discussion about Forth
> design by nitpicking.
Nonsense is bringing same invalid example of "refactoring" over and over
again. That is the nonsense.
--
HE CE3OH...
Of course you have to know that global state is there, and you have to
do something sensible with it.
"global state comes with (sometimes high) price" is true as a general
comment about programming. However, sometimes the cost:benefit
analysis of global state reveals that it's useful. It all depends on
the particular problem.
>>> Why isn't this discussed along with drawing rectangle example?
>>
>> Because it's irrelevant to this simple example.
> It is relevant to this very example, because it introduces global
> state where there wasn't any before.
Of course it introduces global state, because global state helps in
this case. That's the whole idea.
>>> Many people consider this desceptive,
>>
>> Many people? This is a feeble attempt at argumentum ad numerum.
>> You're trying to bolster your argument with a vision of imaginary
>> crowds.
>
> I'm talking about real people.
I don't believe you.
> If there're no problems with Forth and it is easy to use, where's
> the open source software other than toy interpreters? You cannot
> answer any question of this kind, because almost anything is much
> harder to write in Forth, and you don't even understand why it is
> so.
Irrelevant, captain.
>>> and it is desception, because Forth advocates silently skip all
>>> problems that arise from the demonstrated approach.
>>
>> Nonsense. You're trying to hijack a simple discussion about Forth
>> design by nitpicking.
>
> Nonsense is bringing same invalid example of "refactoring" over and
> over again. That is the nonsense.
The question was about the need for locals. My reply, bang on topic,
was to provide an example of where well-factored code made locals
unnecessary. It does.
Andrew.
> Aleksej Saushev <as...@inbox.ru> wrote:
>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>
>>> Aleksej Saushev <as...@inbox.ru> wrote:
>>>
>>>> It's nice that you recall practical examples when global state comes
>>>> with (sometimes high) price.
>>>
>>> This is a bizarre misinterpretation of what Bernd said, which was
>>> that a system with global state has a "huge advantage over the
>>> system you propose". He said that some systems, for example
>>> OpenGL, get this wrong, but so what? It's possible to get things
>>> wrong.
>>
>> Bernd said the very thing I'm trying to get into your head: that you
>> _have_ to maintain global state, if you've got one.
>
> Of course you have to know that global state is there, and you have to
> do something sensible with it.
>
> "global state comes with (sometimes high) price" is true as a general
> comment about programming.
Was it mentioned in the example before I pointed to it?
> However, sometimes the cost:benefit
> analysis of global state reveals that it's useful. It all depends on
> the particular problem.
We don't talk about some "particular" problem, you bring drawing rectangle
as _generic_ example, and when you fail to show the generality you start
drawing discussion into particularities to hide ends.
>>>> Why isn't this discussed along with drawing rectangle example?
>>>
>>> Because it's irrelevant to this simple example.
>
>> It is relevant to this very example, because it introduces global
>> state where there wasn't any before.
>
> Of course it introduces global state, because global state helps in
> this case. That's the whole idea.
Where's the code, that maintains this global state? You tried to prove
that this kind of "factoring" is better and leads to less code.
>>>> Many people consider this desceptive,
>>>
>>> Many people? This is a feeble attempt at argumentum ad numerum.
>>> You're trying to bolster your argument with a vision of imaginary
>>> crowds.
>>
>> I'm talking about real people.
>
> I don't believe you.
Come here, I'll introduce you. One person, I still have contacts to,
tried to use FSL once, and one of problems met was its non-reentrancy.
All because someone tried to factor so hard that introduced global state
and no means to handle it. Skip Carter may still have his e-mail address,
because we submitted bug report at some point.
>> If there're no problems with Forth and it is easy to use, where's
>> the open source software other than toy interpreters? You cannot
>> answer any question of this kind, because almost anything is much
>> harder to write in Forth, and you don't even understand why it is
>> so.
>
> Irrelevant, captain.
It is relevant. You teach how to use Forth properly, but it is still
hard to use while requiring more work, parts because you don't show
how to work around problems you introduce with your approach.
If Forth were easy to use, you'd find much of corresponding code.
>>>> and it is desception, because Forth advocates silently skip all
>>>> problems that arise from the demonstrated approach.
>>>
>>> Nonsense. You're trying to hijack a simple discussion about Forth
>>> design by nitpicking.
>>
>> Nonsense is bringing same invalid example of "refactoring" over and
>> over again. That is the nonsense.
>
> The question was about the need for locals. My reply, bang on topic,
> was to provide an example of where well-factored code made locals
> unnecessary. It does.
You didn't factor the code, you simplified it to the point of irrelevance
instead. You neglected very important part of it, and now you're trying
to hide the fact. Because the very part you neglected requires _at least_
_equivalent_ efforts on memory management. The latter doesn't make the
code neither less complex nor much easier to read or to write.
--
HE CE3OH...
I don't think so. I certainly wouldn't have done so.
>> However, sometimes the cost:benefit analysis of global state
>> reveals that it's useful. It all depends on the particular
>> problem.
> We don't talk about some "particular" problem, you bring drawing
> rectangle as _generic_ example, and when you fail to show the
> generality you start drawing discussion into particularities to hide
> ends.
WTF is a "generic example"? It's an example, that's all.
>>>>> Why isn't this discussed along with drawing rectangle example?
>>>>
>>>> Because it's irrelevant to this simple example.
>>
>>> It is relevant to this very example, because it introduces global
>>> state where there wasn't any before.
>>
>> Of course it introduces global state, because global state helps in
>> this case. That's the whole idea.
>
> Where's the code, that maintains this global state? You tried to
> prove that this kind of "factoring" is better and leads to less
> code.
We've been through this already. I said "That depends. If you moved
somewhere during of a word, then you know where you moved to, so you
can go back there. If you didn't, then the initial cursor position
can be saved then restored. Effectively, the cursor position is
passed to the word as an initial argument."
>>>>> Many people consider this desceptive,
>>>>
>>>> Many people? This is a feeble attempt at argumentum ad numerum.
>>>> You're trying to bolster your argument with a vision of imaginary
>>>> crowds.
>>>
>>> I'm talking about real people.
>>
>> I don't believe you.
>
> Come here, I'll introduce you. One person, I still have contacts
> to, tried to use FSL once, and one of problems met was its
> non-reentrancy. All because someone tried to factor so hard that
> introduced global state and no means to handle it. Skip Carter may
> still have his e-mail address, because we submitted bug report at
> some point.
I wouldn't argue with him. The lack of re-entrancy in the FSL is a
real problem. It can be fixed easily enough, of course, but it is a
problem.
However, that is not the same as:
>> Why isn't this discussed along with drawing rectangle example?
> Because it's irrelevant to this simple example.
> > Many people consider this desceptive,
A set of library routines to calculate mathematical functions should
probably be re-entrant, for all the obvious reasons. It's a totally
different case.
>>> If there're no problems with Forth and it is easy to use, where's
>>> the open source software other than toy interpreters? You cannot
>>> answer any question of this kind, because almost anything is much
>>> harder to write in Forth, and you don't even understand why it is
>>> so.
>>
>> Irrelevant, captain.
>
> It is relevant. You teach how to use Forth properly, but it is still
> hard to use while requiring more work, parts because you don't show
> how to work around problems you introduce with your approach.
In this case, I don't think there are any.
> If Forth were easy to use, you'd find much of corresponding code.
>
>>>>> and it is desception, because Forth advocates silently skip all
>>>>> problems that arise from the demonstrated approach.
>>>>
>>>> Nonsense. You're trying to hijack a simple discussion about Forth
>>>> design by nitpicking.
>>>
>>> Nonsense is bringing same invalid example of "refactoring" over and
>>> over again. That is the nonsense.
>>
>> The question was about the need for locals. My reply, bang on topic,
>> was to provide an example of where well-factored code made locals
>> unnecessary. It does.
>
> You didn't factor the code, you simplified it to the point of
> irrelevance instead.
Simplification is the goal. This is Forth.
> You neglected very important part of it, and now you're trying to
> hide the fact. Because the very part you neglected requires _at
> least_ _equivalent_ efforts on memory management.
There is no adverse memory management consequence to maintaining a
cursor position as global state. If anything doing so makes memory
management easier, since the task doing the drawing doesn't have to
remember where it is as part of its local state.
Andrew.
> Aleksej Saushev <as...@inbox.ru> wrote:
>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>
>>> Aleksej Saushev <as...@inbox.ru> wrote:
>>>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>>>
>>>>> Aleksej Saushev <as...@inbox.ru> wrote:
>>>>>
>>>>>> It's nice that you recall practical examples when global state comes
>>>>>> with (sometimes high) price.
>>>>>
>>>>> This is a bizarre misinterpretation of what Bernd said, which was
>>>>> that a system with global state has a "huge advantage over the
>>>>> system you propose". He said that some systems, for example
>>>>> OpenGL, get this wrong, but so what? It's possible to get things
>>>>> wrong.
>>>>
>>>> Bernd said the very thing I'm trying to get into your head: that you
>>>> _have_ to maintain global state, if you've got one.
>>>
>>> Of course you have to know that global state is there, and you have to
>>> do something sensible with it.
>>>
>>> "global state comes with (sometimes high) price" is true as a general
>>> comment about programming.
>>
>> Was it mentioned in the example before I pointed to it?
>
> I don't think so. I certainly wouldn't have done so.
And that's one of reasons why Forth sucks so much: its advocates bring
invalid examples and don't even understand why they're invalid.
>>> However, sometimes the cost:benefit analysis of global state
>>> reveals that it's useful. It all depends on the particular
>>> problem.
>
>> We don't talk about some "particular" problem, you bring drawing
>> rectangle as _generic_ example, and when you fail to show the
>> generality you start drawing discussion into particularities to hide
>> ends.
>
> WTF is a "generic example"? It's an example, that's all.
What is it meant to demonstrate then? How to write shit code?
Because that's what it demonstrates, and this doesn't make Forth smell
better.
>>>>>> Why isn't this discussed along with drawing rectangle example?
>>>>>
>>>>> Because it's irrelevant to this simple example.
>>>
>>>> It is relevant to this very example, because it introduces global
>>>> state where there wasn't any before.
>>>
>>> Of course it introduces global state, because global state helps in
>>> this case. That's the whole idea.
>>
>> Where's the code, that maintains this global state? You tried to
>> prove that this kind of "factoring" is better and leads to less
>> code.
>
> We've been through this already. I said "That depends. If you moved
> somewhere during of a word, then you know where you moved to, so you
> can go back there. If you didn't, then the initial cursor position
> can be saved then restored. Effectively, the cursor position is
> passed to the word as an initial argument."
"That depends" isn't interesting to anyone, that "that depends" is known
since Paracelsus. You've got to show how it depends.
What does your example demonstrate? How to write without locals?
That isn't interesting, unless it does make code better in any way.
>>>>>> Many people consider this desceptive,
>>>>>
>>>>> Many people? This is a feeble attempt at argumentum ad numerum.
>>>>> You're trying to bolster your argument with a vision of imaginary
>>>>> crowds.
>>>>
>>>> I'm talking about real people.
>>>
>>> I don't believe you.
>>
>> Come here, I'll introduce you. One person, I still have contacts
>> to, tried to use FSL once, and one of problems met was its
>> non-reentrancy. All because someone tried to factor so hard that
>> introduced global state and no means to handle it. Skip Carter may
>> still have his e-mail address, because we submitted bug report at
>> some point.
>
> I wouldn't argue with him. The lack of re-entrancy in the FSL is a
> real problem. It can be fixed easily enough, of course, but it is a
> problem.
No, it cannot be easily fixed, because you have problems even with
understanding that this presents real usability issues.
> However, that is not the same as:
>
>>> Why isn't this discussed along with drawing rectangle example?
>
>> Because it's irrelevant to this simple example.
>
>> > Many people consider this desceptive,
>
> A set of library routines to calculate mathematical functions should
> probably be re-entrant, for all the obvious reasons. It's a totally
> different case.
That's exactly the same case, because a set of graphical routines should
be reentrant as well. And pretty any set of routines should, unless
there is a real reason why it shouldn't.
Again, what is your example to demonstrate?
>>>> If there're no problems with Forth and it is easy to use, where's
>>>> the open source software other than toy interpreters? You cannot
>>>> answer any question of this kind, because almost anything is much
>>>> harder to write in Forth, and you don't even understand why it is
>>>> so.
>>>
>>> Irrelevant, captain.
>>
>> It is relevant. You teach how to use Forth properly, but it is still
>> hard to use while requiring more work, parts because you don't show
>> how to work around problems you introduce with your approach.
>
> In this case, I don't think there are any.
What's the point in your example then? Whom is it addressed to?
>>>>>> and it is desception, because Forth advocates silently skip all
>>>>>> problems that arise from the demonstrated approach.
>>>>>
>>>>> Nonsense. You're trying to hijack a simple discussion about Forth
>>>>> design by nitpicking.
>>>>
>>>> Nonsense is bringing same invalid example of "refactoring" over and
>>>> over again. That is the nonsense.
>>>
>>> The question was about the need for locals. My reply, bang on topic,
>>> was to provide an example of where well-factored code made locals
>>> unnecessary. It does.
>>
>> You didn't factor the code, you simplified it to the point of
>> irrelevance instead.
>
> Simplification is the goal. This is Forth.
If you easily sacrifice use to simplificity, then Forth sucks.
>> You neglected very important part of it, and now you're trying to
>> hide the fact. Because the very part you neglected requires _at
>> least_ _equivalent_ efforts on memory management.
>
> There is no adverse memory management consequence to maintaining a
> cursor position as global state. If anything doing so makes memory
> management easier, since the task doing the drawing doesn't have to
> remember where it is as part of its local state.
The task of drawing requires saving and restoring global state.
How do you maintain it? Where do you save it, when you need it?
--
HE CE3OH...
And that's one of reasons why Forth sucks so much: its advocates bring
invalid examples and don't even understand why they're invalid. "
Hmmm... You don't like Forth much do you? I wonder why you bother.
>Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>> There are two things you can do at this point: patch
>> things up using locals or change the way your code is factored. The
>> latter is almost always better, and it's the reason most people
>> teaching Forth don't introduce locals at the beginning.
>
>Try proving it.
Andrew hasn't defined "better" in this instance. I'm defining
better as shorter and faster. MPE has *measured* the difference
using the VFX compilers on x86 and ARM. For ARM7, as I have said
several times before, code without locals averages about 25%
shorter and 50% faster. The reason is that, without locals, VFX
makes better use of registers and reduces memory operations.
We could improve code generation for locals, but we have not
done it (yet).
>"Thinking Forth" is obsolete, many opinions it promotes were proved
>wrong in recent 20 years.
I would rather say that technology has changed in the last 20 years.
In the main, "Thinking Forth" is still a good read - providing that
the reader understands that the book is 20+ years old. This is true
of many computing books of the period.
I'm getting a bit tired of your "attack Forth" attitude. Most of
the attacks you make are really about library code, or the lack of
it. This says nothing about the language itself, more about the
readers of c.l.f.
Over the last week I have been implementing a disassembler for a
rather complex instruction set. In the spirit of "throw one away",
I am in the process of rewriting the disassembler to take advantage
of Forth as an extensible language with more work done at compile
time. The size of the source code has halved and it's much more
readable.
My book of a few years ago
http://www.mpeforth.com/arena/ProgramForth.pdf
has several discussions on this topic. A second edition may appear
next year, "ample spare time" permitting.
It looks like he's forced to use Forth, and doesn't like it. Unlike other
trolls here, he actually can use Forth, can write at least small example
programs, and his bug reports make sense (despite the name-calling involved
in them). It's however obvious that he struggles with Forth. Or maybe he's
just generally grumpy.
I've already answered that.
>> We've been through this already. I said "That depends. If you moved
>> somewhere during of a word, then you know where you moved to, so you
>> can go back there. If you didn't, then the initial cursor position
>> can be saved then restored. Effectively, the cursor position is
>> passed to the word as an initial argument."
>
> "That depends" isn't interesting to anyone, that "that depends" is known
> since Paracelsus. You've got to show how it depends.
Please read the second sentence, which explains why it depends, and
what it depends on.
> What does your example demonstrate? How to write without locals?
I've already answered that.
>>> One person, I still have contacts to, tried to use FSL once, and
>>> one of problems met was its non-reentrancy. All because someone
>>> tried to factor so hard that introduced global state and no means
>>> to handle it. Skip Carter may still have his e-mail address,
>>> because we submitted bug report at some point.
>>
>> The lack of re-entrancy in the FSL is a real problem. It can be
>> fixed easily enough, of course, but it is a problem.
>
> No, it cannot be easily fixed, because you have problems even with
> understanding that this presents real usability issues.
I know that the lack of re-entrancy in the FSL presents real usability
issues. We've discussed that problem before in this newsgroup.
However, your comment is a non sequitur: my understanding, or the lack
thereof, can have no effect on whether the FSL re-entrancy problem can
easily be fixed.
>> A set of library routines to calculate mathematical functions should
>> probably be re-entrant, for all the obvious reasons. It's a totally
>> different case.
>
> That's exactly the same case, because a set of graphical routines should
> be reentrant as well. And pretty any set of routines should, unless
> there is a real reason why it shouldn't.
I explained why global state is useful in this case. So did Bernd.
You're going around in circles, ignoring people's replies and asking
the same questions as though they had not been answered.
>>>> The question was about the need for locals. My reply, bang on
>>>> topic, was to provide an example of where well-factored code made
>>>> locals unnecessary. It does.
>>> You neglected very important part of it, and now you're trying to
>>> hide the fact. Because the very part you neglected requires _at
>>> least_ _equivalent_ efforts on memory management.
>>
>> There is no adverse memory management consequence to maintaining a
>> cursor position as global state. If anything doing so makes memory
>> management easier, since the task doing the drawing doesn't have to
>> remember where it is as part of its local state.
>
> The task of drawing requires saving and restoring global state.
> How do you maintain it?
Most of the time you don't need to maintain it. That's the whole
point of having the cursor position associated with the device.
> Where do you save it, when you need it?
It depends on the design of the application, of course: there is no
need for any special save/restore mechanism for two integers!
However, the return stack would be a common choice.
Andrew.
You asked the same question before, and I answered you. So, would you be
so kind to reread that answer, if you're so short of memory?
--
HE CE3OH...
What does the lack of library code say about the readers of c.l.f?
- 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: http://www.forth200x.org/forth200x.html
EuroForth 2009: http://www.euroforth.org/ef09/
>steph...@mpeforth.com (Stephen Pelc) writes:
>>I'm getting a bit tired of your "attack Forth" attitude. Most of
>>the attacks you make are really about library code, or the lack of
>>it. This says nothing about the language itself, more about the
>>readers of c.l.f.
>
>What does the lack of library code say about the readers of c.l.f?
That they don't contribute what Aleksej wants?
I think that says it all. LOL!
Especially last sentence ;)
Ok, but in that respect they do not differ from anybody else in the
world, so it says nothing particular about the readers of c.l.f.
> Aleksej Saushev <as...@inbox.ru> wrote:
>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>
>>> Aleksej Saushev <as...@inbox.ru> wrote:
>>>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>>>
>>>>> However, sometimes the cost:benefit analysis of global state
>>>>> reveals that it's useful. It all depends on the particular
>>>>> problem.
>>>
>>>> We don't talk about some "particular" problem, you bring drawing
>>>> rectangle as _generic_ example, and when you fail to show the
>>>> generality you start drawing discussion into particularities to
>>>> hide ends.
>>>
>>> WTF is a "generic example"? It's an example, that's all.
>>
>> What is it meant to demonstrate then?
>
> I've already answered that.
I'm not satisfied by your answer. You've failed in your demonstration
how introducing global state your way improves the code.
You insist that it depends on particular problem, while it is not.
If that's all what you're able to say, then it's your disability as
programmer independently of language. The problem of handling the state
is language-independent.
>>> We've been through this already. I said "That depends. If you moved
>>> somewhere during of a word, then you know where you moved to, so you
>>> can go back there. If you didn't, then the initial cursor position
>>> can be saved then restored. Effectively, the cursor position is
>>> passed to the word as an initial argument."
>>
>> "That depends" isn't interesting to anyone, that "that depends" is known
>> since Paracelsus. You've got to show how it depends.
>
> Please read the second sentence, which explains why it depends, and
> what it depends on.
This doesn't depend on anything, you broke the code by your "refactoring,"
instead of working it became conditionally working, and those conditions
don't hold in general and in practice.
What protocol do you propose to maintain state and why I have to
pull it out of you for several days, while it is your responsibility to
show it beforehand, right at the time when you introduce the state?
>> What does your example demonstrate? How to write without locals?
>
> I've already answered that.
You gave wrong answer and I demonstrated it.
>>>> One person, I still have contacts to, tried to use FSL once, and
>>>> one of problems met was its non-reentrancy. All because someone
>>>> tried to factor so hard that introduced global state and no means
>>>> to handle it. Skip Carter may still have his e-mail address,
>>>> because we submitted bug report at some point.
>
>>> The lack of re-entrancy in the FSL is a real problem. It can be
>>> fixed easily enough, of course, but it is a problem.
>>
>> No, it cannot be easily fixed, because you have problems even with
>> understanding that this presents real usability issues.
>
> I know that the lack of re-entrancy in the FSL presents real usability
> issues. We've discussed that problem before in this newsgroup.
>
> However, your comment is a non sequitur: my understanding, or the lack
> thereof, can have no effect on whether the FSL re-entrancy problem can
> easily be fixed.
Your lack of understanding that global state presents major problem
demonstrates that this is inherent to Forth. And thus neither FSL,
nor any other library can be easily fixed. Your ignorance of anything
outside Forth almost warrants that this is hardly to be fixed at all.
>>> A set of library routines to calculate mathematical functions should
>>> probably be re-entrant, for all the obvious reasons. It's a totally
>>> different case.
>>
>> That's exactly the same case, because a set of graphical routines should
>> be reentrant as well. And pretty any set of routines should, unless
>> there is a real reason why it shouldn't.
>
> I explained why global state is useful in this case. So did Bernd.
> You're going around in circles, ignoring people's replies and asking
> the same questions as though they had not been answered.
Oh, you believe that Bernd examples prove your point!
I have to upset you, Bernd examples prove exactly what I'm telling you
from the very beginning, that immediatly after you introduce global state
you have to introduce state maintainance protocol in general and state
save/restore and/or preservation constructs in particular.
>>>>> The question was about the need for locals. My reply, bang on
>>>>> topic, was to provide an example of where well-factored code made
>>>>> locals unnecessary. It does.
>
>>>> You neglected very important part of it, and now you're trying to
>>>> hide the fact. Because the very part you neglected requires _at
>>>> least_ _equivalent_ efforts on memory management.
>>>
>>> There is no adverse memory management consequence to maintaining a
>>> cursor position as global state. If anything doing so makes memory
>>> management easier, since the task doing the drawing doesn't have to
>>> remember where it is as part of its local state.
>>
>> The task of drawing requires saving and restoring global state.
>> How do you maintain it?
>
> Most of the time you don't need to maintain it. That's the whole
> point of having the cursor position associated with the device.
Contrary to your claim, most of the time you have to maintain it,
when you use anything more complex than teletype-like interface.
>> Where do you save it, when you need it?
>
> It depends on the design of the application, of course: there is no
> need for any special save/restore mechanism for two integers!
So, what's the purpose of your example again?
To show how to write shit code?
Because you explain how to "improve" code in Forth and break it instead.
In this particular case, particular newcomer has found tolerable way how
to deal with the problem using locals. You're showing him errorneous way
instead.
> However, the return stack would be a common choice.
"You've got to show me."
Do you have any experience with this approach at all?
Because I doubt you have any, otherwise you would show at least some
knowledge.
--
HE CE3OH...
> Aleksej Saushev <as...@inbox.ru> wrote:
>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>
>>> Aleksej Saushev <as...@inbox.ru> wrote:
>>>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>>>>
>>>>> However, sometimes the cost:benefit analysis of global state
>>>>> reveals that it's useful. It all depends on the particular
>>>>> problem.
>>>
>>>> We don't talk about some "particular" problem, you bring drawing
>>>> rectangle as _generic_ example, and when you fail to show the
>>>> generality you start drawing discussion into particularities to
>>>> hide ends.
>>>
>>> WTF is a "generic example"? It's an example, that's all.
>>
>> What is it meant to demonstrate then?
>
> I've already answered that.
I'm not satisfied by your answer. You've failed in your demonstration
how introducing global state your way improves the code.
You insist that it depends on particular problem, while it is not.
If that's all what you're able to say, then it's your disability as
programmer independently of language. The problem of handling the state
is language-independent.
>>> We've been through this already. I said "That depends. If you moved
>>> somewhere during of a word, then you know where you moved to, so you
>>> can go back there. If you didn't, then the initial cursor position
>>> can be saved then restored. Effectively, the cursor position is
>>> passed to the word as an initial argument."
>>
>> "That depends" isn't interesting to anyone, that "that depends" is known
>> since Paracelsus. You've got to show how it depends.
>
> Please read the second sentence, which explains why it depends, and
> what it depends on.
This doesn't depend on anything, you broke the code by your "refactoring,"
instead of working it became conditionally working, and those conditions
don't hold in general and in practice.
What protocol do you propose to maintain state and why I have to
pull it out of you for several days, while it is your responsibility to
show it beforehand, right at the time when you introduce the state?
>> What does your example demonstrate? How to write without locals?
>
> I've already answered that.
You gave wrong answer and I demonstrated it.
>>>> One person, I still have contacts to, tried to use FSL once, and
>>>> one of problems met was its non-reentrancy. All because someone
>>>> tried to factor so hard that introduced global state and no means
>>>> to handle it. Skip Carter may still have his e-mail address,
>>>> because we submitted bug report at some point.
>
>>> The lack of re-entrancy in the FSL is a real problem. It can be
>>> fixed easily enough, of course, but it is a problem.
>>
>> No, it cannot be easily fixed, because you have problems even with
>> understanding that this presents real usability issues.
>
> I know that the lack of re-entrancy in the FSL presents real usability
> issues. We've discussed that problem before in this newsgroup.
>
> However, your comment is a non sequitur: my understanding, or the lack
> thereof, can have no effect on whether the FSL re-entrancy problem can
> easily be fixed.
Your lack of understanding that global state presents major problem
demonstrates that this is inherent to Forth. And thus neither FSL,
nor any other library can be easily fixed. Your ignorance of anything
outside Forth almost warrants that this is hardly to be fixed at all.
>>> A set of library routines to calculate mathematical functions should
>>> probably be re-entrant, for all the obvious reasons. It's a totally
>>> different case.
>>
>> That's exactly the same case, because a set of graphical routines should
>> be reentrant as well. And pretty any set of routines should, unless
>> there is a real reason why it shouldn't.
>
> I explained why global state is useful in this case. So did Bernd.
> You're going around in circles, ignoring people's replies and asking
> the same questions as though they had not been answered.
Oh, you believe that Bernd examples prove your point!
I have to upset you, Bernd examples prove exactly what I'm telling you
from the very beginning, that immediatly after you introduce global state
you have to introduce state maintainance protocol in general and state
save/restore and/or preservation constructs in particular.
>>>>> The question was about the need for locals. My reply, bang on
>>>>> topic, was to provide an example of where well-factored code made
>>>>> locals unnecessary. It does.
>
>>>> You neglected very important part of it, and now you're trying to
>>>> hide the fact. Because the very part you neglected requires _at
>>>> least_ _equivalent_ efforts on memory management.
>>>
>>> There is no adverse memory management consequence to maintaining a
>>> cursor position as global state. If anything doing so makes memory
>>> management easier, since the task doing the drawing doesn't have to
>>> remember where it is as part of its local state.
>>
>> The task of drawing requires saving and restoring global state.
>> How do you maintain it?
>
> Most of the time you don't need to maintain it. That's the whole
> point of having the cursor position associated with the device.
Contrary to your claim, most of the time you have to maintain it,
when you use anything more complex than teletype-like interface.
>> Where do you save it, when you need it?
>
> It depends on the design of the application, of course: there is no
> need for any special save/restore mechanism for two integers!
So, what's the purpose of your example again?
To show how to write shit code?
Because you explain how to "improve" code in Forth and break it instead.
In this particular case, particular newcomer has found tolerable way how
to deal with the problem using locals. You're showing him errorneous way
instead.
> However, the return stack would be a common choice.
"You've got to show me."
> On Thu, 22 Oct 2009 14:53:21 +0400, Aleksej Saushev <as...@hotbox.ru>
> wrote:
>
>>Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>
>>> There are two things you can do at this point: patch
>>> things up using locals or change the way your code is factored. The
>>> latter is almost always better, and it's the reason most people
>>> teaching Forth don't introduce locals at the beginning.
>>
>>Try proving it.
>
> Andrew hasn't defined "better" in this instance. I'm defining
> better as shorter and faster. MPE has *measured* the difference
> using the VFX compilers on x86 and ARM. For ARM7, as I have said
> several times before, code without locals averages about 25%
> shorter and 50% faster. The reason is that, without locals, VFX
> makes better use of registers and reduces memory operations.
>
> We could improve code generation for locals, but we have not
> done it (yet).
"Shorter" cannot be better, because if that were true languages would
compete in their terseness. This doesn't happen. Python is gaining more
and more acceptance instead, partly due to its "programs are written for
humans to read" decision. "Faster" isn't "better" for similar reasons.
Since you refer to modern state of the technology, you understand it,
I hope.
>>"Thinking Forth" is obsolete, many opinions it promotes were proved
>>wrong in recent 20 years.
>
> I would rather say that technology has changed in the last 20 years.
> In the main, "Thinking Forth" is still a good read - providing that
> the reader understands that the book is 20+ years old. This is true
> of many computing books of the period.
If "TF" weren't presented like "Quran" or "Bible," there would be no
ground for discussion. But this isn't the fact. The fact is that
it was suggested to "improve" tolerably clear code with "locals-free"
one, and the latter was completely unreadable and incorrect shit.
> My book of a few years ago
> http://www.mpeforth.com/arena/ProgramForth.pdf
> has several discussions on this topic. A second edition may appear
> next year, "ample spare time" permitting.
One of problems with Forth is that newcomer has no chance to learn more
advanced except by doing everything himself. Judging from TOC, your book
is more of basic level.
--
HE CE3OH...
> MPE has *measured* the difference
> using the VFX compilers on x86 and ARM. For ARM7, as I have said
> several times before, code without locals averages about 25%
> shorter and 50% faster. The reason is that, without locals, VFX
> makes better use of registers and reduces memory operations.
That's interesting. I wonder what the typical (if there can be such a
thing here) difference in performance and code size is on popular
Forths these days. I know that on PowerMops with a PowerPC Mike
Hore's optimizer will typically yield faster and smaller code with
locals than without. The latest version of Carbon MacForth uses over
500 definitions with locals in its standard build as delivered to
customers. It runs quite spritely even on a rather meager (slow)
Macintosh. There is no warning in the docs that I can see to avoid
locals in Carbon MacForth for any reason at all. Granted the
following is dated, but here are a few snippets from Don Colburn's
1986 manual for MacForth Plus (680x0 processors): "The MacForth
implementation of locals is such that there is little or no
performance penalty for their use. In fact in many cases the execution
speed is increased with the use of locals." No where in the
documentation does Don warn that using locals could interfere with
factoring or lead to "poorly written code" for whatever reason.
Now perhaps these are special cases because these three Forths are
full-featured desktop PC Forths and not used for creating embedded
applications.
-Doug
>Granted the
>following is dated, but here are a few snippets from Don Colburn's
>1986 manual for MacForth Plus (680x0 processors): "The MacForth
>implementation of locals is such that there is little or no
>performance penalty for their use. In fact in many cases the execution
>speed is increased with the use of locals."
Compared to what? Compared to global variables, the instructions to
access locals are shorter, which usually means faster.
On CPUs with 16 registers and locals, the Forth VM uses 4 or 5
registers, and register spills to deep stack are rare in a basic
block, unlike in an x86 with only 8 registers.
On RISC machines with 32 registers, it is easy to reserve a register
block for locals. However, compiler complexity goes up if you then
find that you need the address of a local.
In VFX Forth on x86, we're restricted in what we can do because a
major client is always demanding faster compilation of 850,000 lines
of source code - currently below 20 seconds on a fast machine.
>No where in the
>documentation does Don warn that using locals could interfere with
>factoring or lead to "poorly written code" for whatever reason.
Don was a good Forth programmer! The danger is not good programmers
and locals in Forth, but poor/average programmers and locals in Forth.
Fortunately, Forth-94 does not feature taking the address of a local.
In Gforth, if you want a local with an address, you have to use a
variable-flavoured local (normal locals behave like values, not like
variables, and as for values you cannot take their address), and you
get that by defining it as such (e.g., { W^ x } for a
variable-flavoured local X). AFAIK nobody uses variable-flavoured
locals, so the desire to take the address of a local appears to be
very small.
If your Forth has an extension that allows taking the address of a
normal, value-flavoured local, then any compiler complexity for
supporting this extension is due to this extension and how you
designed it, not due to locals.
Hmm, the new locals syntax {: ... :} gives an opportunity for your
system to support fast locals: You could let locals defined with the
new syntax be non-addressable unless they are defined in a special way
(i.e. with some prefix, maybe ADDR:). Legacy programs would continue
to work and continue to have slow locals, but new programs or adjusted
programs would have fast locals even on your Forth system.
If you provide the same benchmark with locals and without, we can
measure it, and you will get numbers that can be compared between
systems.
Anyway, it's not these days, but when locals were introduced in
Gforth, I made a few measurements [ertl94l], and the results were a
slowdown from using locals by a factor of 1.32 on MAX and a factor of
1.18 on STRCMP.
@InProceedings{ertl94l,
author = "M. Anton Ertl",
title = "Automatic Scoping of Local Variables",
booktitle = "EuroForth~'94 Conference Proceedings",
year = "1994",
address = "Winchester, UK",
pages = "31--37",
URL = "http://www.complang.tuwien.ac.at/papers/ertl94l.ps.gz",
abstract = "In the process of lifting the restrictions on using
locals in Forth, an interesting problem poses itself:
What does it mean if a local is defined in a control
structure? Where is the local visible? Since the user
can create every possible control structure in ANS
Forth, the answer is not as simple as it may seem.
Ideally, the local is visible at a place if the control
flow {\em must} pass through the definition of the
local to reach this place. This paper discusses locals
in general, the visibility problem, its solution, the
consequences and the implementation as well as related
programming style questions.",
> > Aleksej Saushev <as...@inbox.ru> wrote:
> >> Andrew Haley <a...@littlepinkcloud.invalid> writes:
> >>
> >>> Aleksej Saushev <as...@inbox.ru> wrote:
> >>>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
> >>>>
> >>>>> However, sometimes the cost:benefit analysis of global state
> >>>>> reveals that it's useful. It all depends on the particular
> >>>>> problem.
> >>>
> >>>> We don't talk about some "particular" problem, you bring drawing
> >>>> rectangle as _generic_ example, and when you fail to show the
> >>>> generality you start drawing discussion into particularities to
> >>>> hide ends.
> >>>
> >>> WTF is a "generic example"? It's an example, that's all.
> >>
> >> What is it meant to demonstrate then?
> >
> > I've already answered that.
> I'm not satisfied by your answer.
The problem is that you will only ever be satisfied with answers of
the form "I agree with you." No matter what answer is given to you,
if it's not one that fits with your mindset it isn't an answer, so you
feel free to ask the same question again, in the vain hope of getting
a response that suits you. Only when it is in agreement will you deem
it to be a legitimate answer, but that never happens.
So it is with this question of graphics state: you are convinced that
global state presents great problems no matter what the situation, so
anyone proposing the use of such state must solve a great "problem".
This is impossible, of course, because the problem is so ill-defined
that it can't be answered with anything specific. I suspect this is
deliberate: if anyone does respond with something specific, you can
say "Ah, but that doesn't solve the *real* problem."
Andrew.
> On RISC machines with 32 registers, it is easy to reserve a register
> block for locals. However, compiler complexity goes up if you then
> find that you need the address of a local.
I'm pretty sure that the design of locals in Standard Forth was
intended to allow the use of registers, and that standard locals may
not be addressed for that reason.
If I remember correctly, MPE has a syntax for local buffers, so surely
that can be used for locals that must be addressable, can't it?
How often do people end up taking the address of a local, anyway? I
know it's done a lot in C, but the main reason for that is C functions
can only return one value, so it's a fairly common idiom to do things
like
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
where sendfile() returns two things, a size and an offset. In Forth
you'd return both of these on the stack.
Let me guess: if you're calling sendfile() in a C library, you have to
use the C idiom, so you need to take the address of a local for that?
> Don was a good Forth programmer! The danger is not good programmers
> and locals in Forth, but poor/average programmers and locals in
> Forth.
Quite.
Andrew.
Sorry. Next sentences in the manual: "This is especially true of
definitions that contain relatively heavy stack manipulations or use
variables to hold values. Another benefit is that the total object
space of a definition is often reduced with the use of locals."
-Doug
> If you provide the same benchmark with locals and without, we can
> measure it, and you will get numbers that can be compared between
> systems.
Yes. That would be the way to do it.
> Anyway, it's not these days, but when locals were introduced in
> Gforth, I made a few measurements [ertl94l], and the results were a
> slowdown from using locals by a factor of 1.32 on MAX and a factor of
> 1.18 on STRCMP.
OK. There are a couple of data points.
> author = "M. Anton Ertl",
> title = "Automatic Scoping of Local Variables",
> URL = "http://www.complang.tuwien.ac.at/papers/ertl94l.ps.gz",
That is a very interesting read. Thank you.
-Doug
> Aleksej Saushev <as...@inbox.ru> wrote:
>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>
>> > Aleksej Saushev <as...@inbox.ru> wrote:
>> >> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>> >>
>> >>> Aleksej Saushev <as...@inbox.ru> wrote:
>> >>>> Andrew Haley <a...@littlepinkcloud.invalid> writes:
>> >>>>
>> >>>>> However, sometimes the cost:benefit analysis of global state
>> >>>>> reveals that it's useful. It all depends on the particular
>> >>>>> problem.
>> >>>
>> >>>> We don't talk about some "particular" problem, you bring drawing
>> >>>> rectangle as _generic_ example, and when you fail to show the
>> >>>> generality you start drawing discussion into particularities to
>> >>>> hide ends.
>> >>>
>> >>> WTF is a "generic example"? It's an example, that's all.
>> >>
>> >> What is it meant to demonstrate then?
>> >
>> > I've already answered that.
>
>> I'm not satisfied by your answer.
>
> The problem is that you will only ever be satisfied with answers of
> the form "I agree with you." No matter what answer is given to you,
> if it's not one that fits with your mindset it isn't an answer, so you
> feel free to ask the same question again, in the vain hope of getting
> a response that suits you. Only when it is in agreement will you deem
> it to be a legitimate answer, but that never happens.
This is simply lie. You fail to provide either demonstrative or correct
example for factoring, thus you're trying to shift the topic. I told you
many times that there exists legitimate answer, but you fail to see it.
All because you're so in love with your belief in Forth "simplicity."
> So it is with this question of graphics state: you are convinced that
> global state presents great problems no matter what the situation, so
> anyone proposing the use of such state must solve a great "problem".
> This is impossible, of course, because the problem is so ill-defined
> that it can't be answered with anything specific. I suspect this is
> deliberate: if anyone does respond with something specific, you can
> say "Ah, but that doesn't solve the *real* problem."
The problem isn't ill-defined. It's you who view it that way, because
you don't seem to know much outside your narrow Forth area.
The situation is this: a newcomer posts code, you start "improving" it
and break it by silently introducing the state. You didn't even ask
original poster if he wanted to deal with this state and pay the price.
State does require special care, and you cared nothing of it when you
transformed the code.
--
HE CE3OH...
I imagine it's counter-productive for vendors to argue with
paying customers.
The replacement code provided in a previous post says it all.
It may take time but most users come to the understanding
that adding locals to forth is like adding legs to a snake.
What kind of answer is that?
I don't answer but I'm willing to admit:
these are important questions
these are hard questions
I can't answer or rebut
Groetjes Albert
--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst