It features an integrated assembly interpreter and (more relevantly) a
very nice visualization of a virtual 8086 machine. As the student steps
through code in the tutorial, they can instantly see the changes the code
makes to the registers in the virtual machine. The interpreter is even
capable of single-stepping backwards through the code while visualizing
the effect this has on the machine.[2]
Wouldn't it be great if there was a tutor like this for Forth? Of
course, instead of registers what would be visualized would be the
various Forth stacks (and maybe relevant portions of memory, like the
dictionary space).
What do you think?
---
[1] - http://www.btinternet.com/~btketman/tutpage.html
[2] - Ketman's tutorial looks very primitive (and even requires DOS or a
DOS emulator to run), but the insight it allows in to what's going on
behind the scenes is priceless to a beginner. I strongly encourage
trying it out in an emulator like DOSbox and going through the first
couple of pages of the tutorial.
GreenArrays have a very nice software simulator for their GA144 chip
which looks similar to the Ketman Tutorial :
http://www.greenarrays.com/home/documents/greg/cf-releases.htm
Or download directly from here :
http://www.greenarrays.com/home/documents/greg/code/af-35f-g144a12-PD.zip
Unzip the files, run the file Okad2-41b-pd.exe (under Windows) and
type :
softsim
(It defaults to QWERTY mode, so use the Enter key to enter the
command...)
Then press s and d to run the simulation...
Best regards,
Howerd
On Jun 9, 12:46 am, stavrogin <usenet.20.blacksil...@spamgourmet.com>
wrote:
> I've come across a really fantastic assembly tutorial recently called the
> "Ketman Assembly Language Tutorial".[1]
>
> It features an integrated assembly interpreter and (more relevantly) a
> very nice visualization of a virtual 8086 machine. As the student steps
> through code in the tutorial, they can instantly see the changes the code
> makes to the registers in the virtual machine. The interpreter is even
> capable of single-stepping backwards through the code while visualizing
> the effect this has on the machine.[2]
>
> Wouldn't it be great if there was a tutor like this for Forth? Of
> course, instead of registers what would be visualized would be the
> various Forth stacks (and maybe relevant portions of memory, like the
> dictionary space).
>
> What do you think?
>
> ---
>
> [1] -http://www.btinternet.com/~btketman/tutpage.html
Looking at the GA site they have the Introduction to arrayForth
document as a stand alone set of web pages (plural). Anyone know if
this is available as a PDF or other doc that can be downloaded? They
don't even link these pages back to the main sight so I can tell how
to find them starting from the main page.
Rick
That looks nice. Now if only had an integrated tutorial, ala Ketman.
And there still seems to be a lack of this sort of thing for any ANS
Forth.
The closest thing is "Forth Application Techniques", which is a "lab
manual" used in FORTH Inc's classes. You can download the evaluation
version of SwiftForth and use it to work your way through the book.
Forth is based on a virtual machine that is simple enough for anyone
who's not a vegetable to get their head around. Since you have an
interactive conole, you can explore the behavior of words instantly.
Common practice in Forth is to write small words and test as you go.
This interactive nature means you don't need a single-stepping
debugger. I mean, you can have one, but you're more productive using
the traditional Forth design flow.
-Brad
OTOH, it may be useful to newbies. Win32forth's single stepping
debugger is pretty good. I don't know of a Forth that lets you step
backwards (undo).
-Brad
>OTOH, it may be useful to newbies. Win32forth's single stepping
>debugger is pretty good. I don't know of a Forth that lets you step
>backwards (undo).
Bill Stoddart has presented several papers at EuroForth about a
reversible Forth.
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 have my doubts. I've seen newbies write really tragic Forth code
with the help of a single-stepping debugger with stack view: huge
words with conditionals ten deep. What's worse, I was hired to debug
it. I shudder at the thought even now, many years later.
Andrew.
Funny thing that. It shows that when you compute, you are not
creating information, you are losing information. Every time you
write a register or variable you are deleting its old value. If it is
not saved somewhere it may not be re-calculable. Just goes to show
how much information we are destroying every time we use our
computers! Of course, most of it is nothing we care about.
Rick
Hans Bezemer
.s doesn't help much if the stuff on the stack is execution tokens that
look like opaque numbers. You really want to single step EXECUTE so you
can find out what it is that you're calling.
Thank you for the suggestion, but that's not close to what I was
describing at all. That's a standard way of working through a book or a
tutorial, not a tutorial that's integrated with a simulator that shows
you exactly what the code does step by step (and allows backtracking).
> Forth is based on a virtual machine that is simple enough for anyone
> who's not a vegetable to get their head around.
That's not my experience, not by a long shot. I wouldn't call it a
completely incoherent mess, but some parts of it are very confusing.
I would love to have an interactive display that showed me exactly what
was being done to what when each word is parsed, compiled, and executed.
> Since you have an interactive conole, you can explore the behavior of
> words instantly.
Sure, you could manually check every stack and relevant memory address by
hand as you go along. Or maybe even write some convenience words to help
you do that sort of probing. But it's a far cry from something like
Ketman's tutorial gives an assembly language student.
> Common practice in Forth is to write small words and test as you go.
> This interactive nature means you don't need a single-stepping debugger.
> I mean, you can have one, but you're more productive using the
> traditional Forth design flow.
Well, since there isn't anything close to the Ketman tutorial for Forth,
it's kind of hard to compare. I think it would be very valuable for a
beginner like me. And, in any case, it would detract nothing from Forth,
since you could always still manually poke around in memory and on the
stacks if you wanted to.
It may be simplest to examine the code of an implementation, perhaps one
written in another language. Reading a book like C. H. Ting's "Inside
F83" can also be enlightening. Note that's a pretty obscure book and
I'm sure there are other good ones, but it's one of the few that I
happen to have looked at. Maybe other people here can suggest other
books at that level. The Wikipedia article "Forth language" is also
pretty good.
I looked at a number of Lisp tutorials when I first got interested in
Lisp, but Lisp never really made sense to me until I studied an existing
implementation written in C.
No it's not that easy. Suppose I say
5 CONSTANT x
How does the interactive console help me understand how CONSTANT works?
In executing typical Forth programs, execution tokens are rarely on the
data stack, because although conceptually the VM sends individual xts to
EXECUTE, in practice it operates at a much lower level for performance
(even an ITC implementation).
The standard methodology is to look at the definition you're testing and
type your way through it, examining the stack along the way. Many
Forths have a mode in which the data stack is shown at all times.
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."
==================================================
x .
?
--
Coos
CHForth, 16 bit DOS applications
http://home.hccnet.nl/j.j.haak/forth.html
Perhaps you're right. I'm not a very experienced Forth programmer and
it's quite possible that I'm not well attuned to how Forthers normally
do things. But my own Forth code (what little there is) passes xt's
around quite a lot. It's probably the Lisper in me. Anyway, I had to
deal with this issue.
I guess it could be helpful if .s tried to match up numbers on the stack
with dictionary addresses if the numbers are in that range. gdb does
something like that, for example.
Well, having typed that line, you can test it by typing
x .
...and see what you get. And you can try:
' x 20 - 50 dump
and look for your 5, and see what's around it. Of course, exactly what
that will be will vary from one Forth to another, since implementations
structure their dictionaries differently.
But what's confusing about this description from the Forth Programmer's
Handbook (the book that was recommended)? It also shows a conceptual
diagram of the structure thus defined.
_________________
4.1.3 Constants
The defining word CONSTANT defines a class of words whose behaviors are
as follows:
1. The defining behavior of CONSTANT (used to define members of the
class) creates a header in the dictionary and compiles the number that
is on top of the stack into the dictionary.
2. The instance behavior of CONSTANT (executed by members of the class)
pushes onto the stack the number compiled when the instance was defined.
CONSTANT is used in the following way.
Try this:
1024 CONSTANT 1K
1K . <cr> 1024
Note that you don’t need any words, other than the instance name, to
retrieve the value of a CONSTANT.
____________________
Sure, an animated simulator might be more fun, but they're expensive to
develop, and so far no one has felt the need justifies the effort.
Perhaps you would like to write one? It would be a good learning exercise.
I would recommend as a learning exercise writing more Forth that
*doesn't* pass execution tokens around on the stack. It really isn't
the most appropriate style in most cases. I don't even teach execution
tokens until the 4th day of a 5-day course.
Oops, that's Forth Application Techniques. Handbook's description is:
---------------
The purpose of a CONSTANT is to provide a name for a value which is
referenced often but never changed. There are both single- and
double-precision versions. Figure 7 shows an example of a dictionary
entry built by CONSTANT.
[ figure ]
The syntax for defining constants is:
<value> CONSTANT <name>
For example, you may define:
1000 CONSTANT LIMIT
0 5000 2CONSTANT LIMITS
3141593. 2CONSTANT PI
When a CONSTANT is referenced by name, its value (not its address) is
pushed onto the stack. Similarly, when a 2CONSTANT is referenced, two
stack items are pushed onto the stack. In the case where a 2CONSTANT is
used for two values (as in LIMITS, above), the values are placed on the
stack in the order specified (e.g., 5000 on top, 0 below). In the case
of a double-precision number, the high-order part of the number is on
top of the stack.
----------------
Pick one.
And don't hesitate to ask us about things that are confusing to you!
Sure, but that doesn't tell me how it works. A new word "x" that does a
certain thing has appeared in the vocabulary, through a process of
complete black magic. To understand what really happened, I have to
examine the definition of CONSTANT, something like:
: CONSTANT CREATE , DOES> @ ;
And for that to make sense, I have to understand how the inner and outer
interpreters interact, and how dictionaries and ALLOT and CREATE and the
input stream work, and all that wonderfully clever stuff that make Forth
what it is. I took Stavrogin to me s/he was looking for for that level
of understanding, when s/he asked for "an an interactive display that
showed me exactly what was being done to what when each word is parsed,
compiled, and executed."
I don't think I can reasonably say "I understand Forth" if all I know
about CONSTANT is that makes a symbol with a given value appear out of
nowhere. And the interactive console by itself isn't enough to
understand what it really does.
What are you using for a text book? Don't hesitate to ask us about
things you find confusing!
> I would love to have an interactive display that showed me exactly what
> was being done to what when each word is parsed, compiled, and executed.
>
>> Since you have an interactive console, you can explore the behavior of
>> words instantly.
>
> Sure, you could manually check every stack and relevant memory address by
> hand as you go along. Or maybe even write some convenience words to help
> you do that sort of probing. But it's a far cry from something like
> Ketman's tutorial gives an assembly language student.
Assembly language isn't naturally interactive. Forth is.
>> Common practice in Forth is to write small words and test as you go.
>> This interactive nature means you don't need a single-stepping debugger.
>> I mean, you can have one, but you're more productive using the
>> traditional Forth design flow.
>
> Well, since there isn't anything close to the Ketman tutorial for Forth,
> it's kind of hard to compare. I think it would be very valuable for a
> beginner like me. And, in any case, it would detract nothing from Forth,
> since you could always still manually poke around in memory and on the
> stacks if you wanted to.
Well, I haven't seen that tool (and I didn't have anything like it when
I was learning assembly language), but it sounds like using a flight
simulator to learn to ride a bicycle.
Really, Forth is simple. From my experience teaching people Forth
programming, I find that what confuses them most is that they're
expecting something a lot more complicated than what is actually
happening, looking for some magic that isn't there.
Everything that is unfamiliar seems confusing at first, that's natural.
But rather than look for a complex tool, you'll be better off trying
to understand the simplicity underneath. Ask us questions, we'll help!
That explains how to use CONSTANT but doesn't explain HOW IT WORKS.
I actually think I do mostly understand CONSTANT by now, from the
explanation in the GForth manual:[1]
The classic example is that you can define CONSTANT in this way:
: CONSTANT ( w "name" -- )
CREATE ,
DOES> ( -- w )
@ ;
When you create a constant with 5 CONSTANT five, a set of define-time
actions take place; first a new word five is created, then the value 5
is laid down in the body of five with ,. When five is executed, the
address of the body is put on the stack, and @ retrieves the value
5. The word five has no code of its own; it simply contains a data field
and a pointer to the code that follows DOES> in its defining word. That
makes words created in this way very compact.
It took quite a bit of head scratching for the explanation above to make
sense to me, though, and it's likely that some subtleties still escape
me. Understanding the 2-stack virtual machine is NOT enough for this.
[1] http://www.complang.tuwien.ac.at/forth/gforth/Docs-html/User_002ddefined-Defining-Words.html
The problem with trying to get at that level is that those details vary
with every Forth that has been built. It isn't the minutiae that's
important, it's the concept. I have attempted to explain those concepts;
do the two descriptions of CONSTANT I gave elsewhere in this thread help
you?
> I don't think I can reasonably say "I understand Forth" if all I know
> about CONSTANT is that makes a symbol with a given value appear out of
> nowhere. And the interactive console by itself isn't enough to
> understand what it really does.
CONSTANT associates a value with a name. When the name is executed, the
value will be pushed on the stack. It isn't out of nowhere, it's out of
data space associated with the name. But where that data space is and
how the association is structured is implementation-dependent, and
really, truly, doesn't matter. Do you need to know how each and every C
compiler works (because they vary, too) in order to program in C?
Ok, that's one example implementation. But it's far from the only way
CONSTANT can be implemented. There are, for example, systems that have a
version that works somewhat like this for interactive use, and another
that works inside a colon definition and compiles the value as a
literal, or makes it available to an optimizing compiler to do something
with. Trying to focus on the implementation details is ultimately going
to confuse you more, not less. Try to focus on behavior (semantics),
not implementation.
It's not just more fun, I think it make understanding what's going on
much easier, and speeds up the learning process tremendously. At least
that's the case with assembly language and a tool like Ketman's. And I
think it would be similarly beneficial for learning Forth.
> but they're expensive to develop, and so far no one has felt the need
> justifies the effort. Perhaps you would like to write one? It would
> be a good learning exercise.
So they're expensive to develop, and no one in the history of Forth has
ever made one, but you suggest that a complete beginner make one as a
learning exercise? Sure, I'll get right on that right after I finish
figuring out "create .. does>" :)
Actually, Ketman's tool was developed by the author to help himself
understand assembly better. And it was made by one person... in assembly
language no less. So it is possible. And should be much easier in
Forth, if the language really does make developers 10x or 100x more
productive.
On the other hand, I realize that the Forth community is a small one, and
everyone's busy with their own projects. So i don't really expect
anything to ever come of this. But I'm just throwing the idea out there
because I do think that it would be of great help to newbies.. and in
case anyone with a hankering to make a new Forth tutorial ever feels like
making an innovative and useful tool.
The expense is in thinking up the best design, and probably a lot of
trial and error getting it to work optimally. But most of us follow
demand. The demand we've mostly seen has been for good books, which
we've put a lot of effort into, a convenient user interface (and
SwiftForth has a lot of debugging tools, such as monitors for individual
locations and regions of memory), and software features such as
libraries and examples. That's where we've put our effort.
That's a non sequitur: C doesn't allow me to invent new control
structures. It's all wrapped up inside the compiler. Suppose I have
some functions that only work with even numbers, so I want to write a
word like CONSTANT, except it rounds its stack arg up to the nearest
even number. That is,
6 EVEN-UP X
should do the same thing as 6 CONSTANT X, but 5 EVEN-UP X should round
the 5 up to 6 before defining X. That's a perfectly good Forth
exercise:
: EVEN-UP CREATE 1 + 1 invert and , DOES> @ ;
but there is nothing like it in C. Once I understand how to write
something like EVEN-UP, it suddenly dawn on me that the whole Forth
system can be written that way, and the audacity of the concept almost
knocked me over. There really is magic to it. I think that's the
reason people who look into how Forth works then want to implement it
themselves (the topic of numerous other threads). Lisp has the same
effect on people, as has also been noted elsewhere. C does not. Forth
is in some ways more spiritually similar to Lisp than it is to C.
Yes, defining words do add a different dimension, and I agree that they
can seem magical! But even with defining words, it isn't important to
understand how DOES> works its magic or where the associated data space
is, which is what I understood you to be asking.
In fact, relatively little of the Forth system is actually defined in
terms of DOES> structures, as powerful as they are.
Sure, different implementations are possible. I've still always found
that studying a sample implementation is much better for demystifying
something than trying to understand a handwavey explanation that skips
the relevant details. The semantics of CONSTANT are that it reads a
symbol from the input stream and associates a value with it. But for
even that explanation to make sense, I have to understand what "the
input stream" means, in the sense how it is processed by the text
interpreter. From there it's course pretty simple to understand CREATE
and the surrounding stuff. The explanation in the Gforth manual was
highly enlightening in that regard.
I've been hopping around various books and tutorials. Mostly reading
through "Starting Forth" (which I think is really kind of overrated, but
I'll save the details for another post), the gforth tutorial and manual,
a bit of the "Forth Programming Handbook", and various other tutorials
here and there.
I looked up some Forth books in my university library, but they're all
pretty old. I think the newest one was from 1987 or something. So, while
they may be good books, I'm worried that they won't be too applicable to
modern Forths.
> Don't hesitate to ask us about things you find confusing!
I will. Expect a "create .. does>" confusion/frustration post from
me soon! :)
> Assembly language isn't naturally interactive. Forth is.
True. The value of something like Ketman's tutorial, which includes an
assembly language *interpreter* is much higher for assembly language
than for a language like Forth. But the instant visual feedback
concerning the state of the virtual machine is equally valuable in both.
When that sort of thing is tightly integrated with a tutorial, I think
the combination is unbeatable.
> Well, I haven't seen that tool
Check it out:
http://www.btinternet.com/~btketman/tutpage.html
It runs great under the DOSbox emulator:
Even if you have no interest in assembly, or if you're already an
assembly language guru, it's still pretty cool. Read through the first
couple of pages of the tutorial and use the tool's code-stepping
feature. I don't think you can fail to be impressed. Just imagine having
something like that for Forth, showing the various Forth stacks and
relevant sections of memory.
> (and I didn't have anything like it when I was learning assembly
> language) but it sounds like using a flight simulator to learn to ride
> a bicycle.
The flight simulator analogy is an apt one. People used to learn to fly
without them. Now they exist, and even a little kid can learn quite a
lot about flight by using them. Of course, it's still possible to learn
without them, but their usefulness is pretty undeniable.
> Really, Forth is simple.
Not for me. Of course, the absolute basics like DUP and ROT, the various
arithmetic operators, etc, are all very simple. And even the postfix
notation became almost second nature after a day or so of playing with
it. But I'm still struggling with understanding "create .. does>",
"postpone", "immediate" (especially when used with "postpone"), how
Forth's vocabulary works, compilation vs interpretation semantics, and a
bunch of other stuff.
More on the specifics of what I don't understand in another post.. But
my point is that this is NOT SIMPLE!
Simple is something like LOGO, where you have a turtle that you can move
"FORWARD 10", "RIGHT 90" 4 times to make a box. That's simple.
Juggling the data stack, return stack, floating point stack,
control-flow stack, code pointers, interpreter pointers, compilation vs
interpretation behavior (and how/when to force one or the other), not to
mention all the different portions of memory things could/should be in
is NOT SIMPLE!!!!
(And that's not to mention figuring out how to get Forth to do things
that are a given in so many other languages, like garbage collection,
object orientation, regular expressions, etc..)
Sorry. I'm just a bit frustrated here. I'm really struggling to
understand some of this stuff..
Maybe it's simple for you, but you've been programming in Forth for
decades. I just started. Maybe (hopefully) it will all seem simple to me
eventually. But certainly not now.
> From my experience teaching people Forth programming, I find that what
> confuses them most is that they're expecting something a lot more
> complicated than what is actually happening, looking for some magic
> that isn't there.
It's not expecting some magic that's stumping me. A lot of it has to do
with Forth's inconsistencies and implicit operations.
Some Forth words get what they operate on from what's pushed on the data
stack with the word that comes immediately before them in the source,
others get their input from what the user just typed in the interpreter,
others from words that are typed *after* them.
It's pretty inconsistent. And you can't tell just by looking at a word
where it'll expect input from or what it'll do with the output. It
doesn't help at all that so many Forth words are monosyllabic or (worse)
just a character or two.
And, just to rant on a bit about "Starting Forth" for a second, a lot of
the code in the book has no stack effect comments. And the explanations
are often not complete, leaving the reader to guess at why it does what
it does, or what it does at all.
Trying to read real-world code (as opposed to code in a tutorial) is a
thousand times harder.. especially since it tends to be really poorly
commented and poorly factored.
> Everything that is unfamiliar seems confusing at first, that's
> natural. But rather than look for a complex tool, you'll be better off
> trying to understand the simplicity underneath. Ask us questions,
> we'll help!
Thank you. I really do appreciate the help given in this newsgroup.
Hopefully one day I'll known enough Forth to help out future Forth
newbies, or maybe even write something useful that I can contribute to
the community.
Never having used such a thing, I don't have direct experience with how
helpful it is. It seems to me that a classroom lecture (person
explaining things using a whiteboard) is probably good enough. There
are a lot of video lectures about Haskell and other languages online
these days. Maybe there are also some about Forth.
Yes, I agree that examples are helpful if taken in the right spirit,
which you seem to be doing. Certainly understanding how the input
stream is processed is a fundamental requirement.
I think we're diverging a bit from stavrogin's desire for an automated
debugger of some sort. Although I can imagine what such a tool for
assembly language programming would work, I have more trouble
visualizing one for Forth. Among other things, you have two stacks, a
dictionary, possibly separate data spaces, and the input stream which
could be a large variety of different things. When you're actually
testing a program, you're usually worrying about only a subset of these.
Open Firmware originally (at Sun) had a pretty nice interactive
debugger. Among other things, it included a decompiler that attempted
to show names, although not all names are available in OF packages, even
to the point of showing you the content of DEFER-type words. But even
though it was in the IEEE standard, neither Apple nor IBM chose to
implement it fully, and none of the OF programmers that I worked with at
either company seemed to feel the lack.
Well, what I'd like to see is something that will show me at least where
each of the words in that definition are getting their inputs from and
where they're sending their outputs to, or whatever stack/memory juggling
they're doing.
To take a much simpler example (especially since I'm still struggling to
understand "create .. does>") if we had:
: foo dup + ;
I'd like to be able to tab over the words in this definition,
particularly to the "dup" and see that it takes one word from the data
stack, and outputs another word to the data stack.
So maybe the visualization would show two data stacks, a before and
after, and if the number 2 was on the before stack, then two 2's would be
on the after data stack.
Or maybe just have one data stack, and as I tab from the "dup" to the "+"
the "2" on the data stack would get duplicated before my eyes. And the
data stack could be highlighted somehow to show that was what was being
affected by the "dup" word.
Then, tabbing over the "+" would combine the two 2's on the data stack in
to a 4.
Of course, this sort of thing is not necessary for the super simple
definitions like this. But for more sophisticated definitions that get
their input from a variety of stacks and output them to yet others (or
even send/get them to/from memory), this would be a great help.
Also, exactly how this would all work and what the user of such a
simulation would see is pretty half baked in my mind's eye right now.
Whoever writes it would really have to play around with it and hopefully
get feedback from real newbies as to what works best and what would be
most helpful to show them.
They aren't. Don't bother. You may also benefit from my Forth
Programmer's Handbook, which is included in FORTH, Inc.'s free
SwiftForth evaluation system.
>> Don't hesitate to ask us about things you find confusing!
>
> I will. Expect a "create .. does>" confusion/frustration post from
> me soon! :)
Ok! I did try a new approach to that in Forth Application Techniques.
Do read that carefully!
...
>
>> (and I didn't have anything like it when I was learning assembly
>> language) but it sounds like using a flight simulator to learn to ride
>> a bicycle.
>
> The flight simulator analogy is an apt one. People used to learn to fly
> without them. Now they exist, and even a little kid can learn quite a
> lot about flight by using them. Of course, it's still possible to learn
> without them, but their usefulness is pretty undeniable.
Yes, because airplanes (even the simple ones I used to fly) are
complicated, and mistakes can be fatal. Forth is a bicycle. Not so far
to fall.
>> Really, Forth is simple.
>
> Not for me. Of course, the absolute basics like DUP and ROT, the various
> arithmetic operators, etc, are all very simple. And even the postfix
> notation became almost second nature after a day or so of playing with
> it. But I'm still struggling with understanding "create .. does>",
> "postpone", "immediate" (especially when used with "postpone"), how
> Forth's vocabulary works, compilation vs interpretation semantics, and a
> bunch of other stuff.
>
> More on the specifics of what I don't understand in another post.. But
> my point is that this is NOT SIMPLE!
In the first place, you can do a massive amount of useful programming
without dealing with POSTPONE, IMMEDIATE, vocabularies, and compilation
vs. interpretation semantics (providing you'll accept semantic
descriptions of the structure words like IF without worrying about how
to write your own). Get comfortable with all the basics before worrying
about those. Then you'll be able to see that they aren't complicated,
either.
> Simple is something like LOGO, where you have a turtle that you can move
> "FORWARD 10", "RIGHT 90" 4 times to make a box. That's simple.
>
> Juggling the data stack, return stack, floating point stack,
> control-flow stack, code pointers, interpreter pointers, compilation vs
> interpretation behavior (and how/when to force one or the other), not to
> mention all the different portions of memory things could/should be in
> is NOT SIMPLE!!!!
Mastering stack skills is basic, and the place to start. None of the
rest of that list is essential for 90% of the programming most people
need to do.
> (And that's not to mention figuring out how to get Forth to do things
> that are a given in so many other languages, like garbage collection,
> object orientation, regular expressions, etc..)
>
> Sorry. I'm just a bit frustrated here. I'm really struggling to
> understand some of this stuff..
Concentrate on the basics and get really comfortable with that before
worrying about all this advanced stuff. I think you're trying to grok
calculus before mastering the multiplication tables :-)
> Maybe it's simple for you, but you've been programming in Forth for
> decades. I just started. Maybe (hopefully) it will all seem simple to me
> eventually. But certainly not now.
I have taught hundreds of classes, probably several thousand beginning
Forth programmers, so I do understand the learning curve. I think if
you go chapter-by-chapter through Forth Application Techniques working
the problems, by the time you get to the more advanced sections you'll
be ready. And then ask those questions!
>> From my experience teaching people Forth programming, I find that what
>> confuses them most is that they're expecting something a lot more
>> complicated than what is actually happening, looking for some magic
>> that isn't there.
>
> It's not expecting some magic that's stumping me. A lot of it has to do
> with Forth's inconsistencies and implicit operations.
>
> Some Forth words get what they operate on from what's pushed on the data
> stack with the word that comes immediately before them in the source,
> others get their input from what the user just typed in the interpreter,
> others from words that are typed *after* them.
As a general rule, numeric values are supplied on the data stack so
they're there when the word executes, and text data is supplied after so
the text interpreter can parse it. S" is the only common exception to
that rule.
> It's pretty inconsistent. And you can't tell just by looking at a word
> where it'll expect input from or what it'll do with the output. It
> doesn't help at all that so many Forth words are monosyllabic or (worse)
> just a character or two.
Yes, alas, you do have to memorize a lot of words and their stack
arguments. That's probably the hardest thing about Forth, because the
command set is so very large. In some respects it's more like learning
a new human language than a programming language, since there are so
many words to master.
> And, just to rant on a bit about "Starting Forth" for a second, a lot of
> the code in the book has no stack effect comments. And the explanations
> are often not complete, leaving the reader to guess at why it does what
> it does, or what it does at all.
I do not recommend "Starting Forth" to anyone.
> Trying to read real-world code (as opposed to code in a tutorial) is a
> thousand times harder.. especially since it tends to be really poorly
> commented and poorly factored.
Obviously that depends a lot on the programmer. I've heard so many
JonesForth horror stories!
Most of the real-world code I've worked with at FORTH, Inc. is pretty
easy to read, because we're obsessive about things like formatting,
stack arguments, comments, naming conventions and factoring. But
unfortunately many people aren't as disciplined.
>> Everything that is unfamiliar seems confusing at first, that's
>> natural. But rather than look for a complex tool, you'll be better off
>> trying to understand the simplicity underneath. Ask us questions,
>> we'll help!
>
> Thank you. I really do appreciate the help given in this newsgroup.
> Hopefully one day I'll known enough Forth to help out future Forth
> newbies, or maybe even write something useful that I can contribute to
> the community.
I hope so, too!
You're absolutely right. That is very helpful. And I am very grateful
for the work you and the other members of the Forth community have made
to get these sorts of books, tools, libraries, and examples out there.
I certainly don't mean to imply that a tool like Ketman's tutorial should
replace them, or is better than them. But it could be a useful
supplement.
A number of Forths (including SwiftForth) have stepping debuggers that
will do some of this, actually executing the words. SwiftForth has
quite a few programming aids, I'd be interested in what you think of them.
> Of course, this sort of thing is not necessary for the super simple
> definitions like this. But for more sophisticated definitions that get
> their input from a variety of stacks and output them to yet others (or
> even send/get them to/from memory), this would be a great help.
In practice, you end up memorizing a lot of words. In the beginning,
it's helpful to have a glossary such as in Forth Programmer's Handbook
handy. Many Forths (again, including SwiftForth) let you type:
LOCATE <name>
...and will show you the source for <name>, which should have a stack
comment. As time passes, you'll develop a working vocabulary of words.
As I said in my other post, learning Forth is in some respects a lot
more like learning a new human language, because your ability to express
yourself well depends on acquiring a vocabulary.
Not sure if it's already been mentioned, since I only skimmed the
thread, but also have a look Stephen Pelcs free book, which is here:
http://www.mpeforth.com/books.htm
It's a free PDF download. I found it very helpful.
Mark
Totally agree. Once the penny drops you have a real "OH WOW!" moment
at the cleverness, and also the beautiful simplicity of it. There's no
going back!
Couldn't resist: The code above... Wouldn't the following be simpler?
: EVEN-UP CREATE 1+ $FFFE AND , DOES> @ ; ( assumes 16 bit cell!)
(Note the extra spaces to separate phrases. Something I learned from
Elizabeth Rather's book!)
:-)
Regards
Mark
Mark
That fails in the 64-bit Gforth that I'm using. It doesn't seem worth
introducing a dependency given that there is zero runtime overhead
(the masking happens at compile time) from doing it portably.
Works with 16, 32, 64 and perhaps 128 bit 2-complement system:
: EVEN-UP CREATE 1+ -2 AND , DOES> @ ;
And benefits by not needing hexadecimals.
Or
: EVEN-UP CREATE ALIGNED , DOES> @ ;
This rounds up to the nearest aligned cell.
> (And that's not to mention figuring out how to get Forth to do things
> that are a given in so many other languages, like garbage collection,
> object orientation, regular expressions, etc..)
There are extensions for these 'not given' things. For example, there
are a dozen or so objects extensions. Which one did you want?
> Some Forth words get what they operate on from what's pushed on the data
> stack with the word that comes immediately before them in the source,
> others get their input from what the user just typed in the interpreter,
> others from words that are typed *after* them.
>
> It's pretty inconsistent. And you can't tell just by looking at a word
> where it'll expect input from or what it'll do with the output. It
> doesn't help at all that so many Forth words are monosyllabic or (worse)
> just a character or two.
As has been mentioned, a good Forth will have a built-in programmer's
assist utility for looking up a word's stack effect and a brief
description of the word. In Carbon MacForth, for example, typing ROT
CTRL-Y will pull up a small window with the following:
*********
ROT n1 n2 n3 -- n2 n3 n1
Rotates the top three stack items the third item
is brought to the top.
*********
If the word is in a custom extension, then that source is opened. For
example, typing -ROT CTRL-Y will pull up the following:
*********
[undefined] -ROT [IF]
: -ROT ( n1 n2 n3 -- n3 n1 n2 ) ROT ROT ;
[THEN]
*********
Carbon MacForth's debugging utility is simple but effective. Here is
how it can be used:
trace on debug on
: -ROT ( n1 n2 n3 -- n3 n1 n2 ) ROT ROT ; ok
1 2 3 -rot
: -ROT ( 3 ) \ 1 \ 2 \ 3
ROT ( 3 ) \ 2 \ 3 \ 1
ROT ( 3 ) \ 3 \ 1 \ 2
; ok ( 3 ) \ 3 \ 1 \ 2
The floating point stack would also be shown if it were being used.
Other Forths will do the equivalent and perhaps more.
-Doug
A standard technique is typing word by word, while showing the stack.
As Elizabeth already pointed out, many Forth's have a provision for that.
lina -e
<copyright bla bla>
DO-DEBUG
S[ ] OK
5
S[ 5 ] OK
CONSTANT ciforth ERROR # 5 : EMPTY NAME FOR NEW DEFINITION
S[ ]
5
S[ 5 ] OK
CONSTANT AAP
S[ ] OK
AAP
S[ 5 ]
You should be pretty dense, if that doesn't give you a feel.
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
Oh, I know they're out there. But you have to learn how to use them, and
the more of this sort of thing you use the more complexity there is.
>> Some Forth words get what they operate on from what's pushed on the
>> data stack with the word that comes immediately before them in the
>> source, others get their input from what the user just typed in the
>> interpreter, others from words that are typed *after* them.
>>
>> It's pretty inconsistent. And you can't tell just by looking at a word
>> where it'll expect input from or what it'll do with the output. It
>> doesn't help at all that so many Forth words are monosyllabic or
>> (worse) just a character or two.
>
> As has been mentioned, a good Forth will have a built-in programmer's
> assist utility for looking up a word's stack effect and a brief
> description of the word. In Carbon MacForth, for example, typing ROT
> CTRL-Y will pull up a small window with the following:
>
> *********
> ROT n1 n2 n3 -- n2 n3 n1
> Rotates the top three stack items the third item is brought to the
> top.
> *********
Sure. But in many other languages the arguments to a function are
explicit rather than implicit. So you'd write something like:
foo( bar, baz ) ;
and it's plain from a glance at the source that the "foo" function is
receiving "bar" as its first argument and "baz" as its second argument.
But there is no such explicit argument passing in Forth. So you couldn't
get this information just by glancing at the source of a Forth program
unless you've memorized the words in each of the definition, or unless
you look up each word in the documentation.
And for poorly documented words the pain of figuring out just where their
input is coming from is that much harder in Forth than in many other
languages where, again, a simple glance at the source of the function
will tell you what the function inputs are.
> Carbon MacForth's debugging utility is simple but effective. Here is
> how it can be used:
>
> trace on debug on
> : -ROT ( n1 n2 n3 -- n3 n1 n2 ) ROT ROT ; ok
>
> 1 2 3 -rot
>
> : -ROT ( 3 ) \ 1 \ 2 \ 3
> ROT ( 3 ) \ 2 \ 3 \ 1
> ROT ( 3 ) \ 3 \ 1 \ 2
> ; ok ( 3 ) \ 3 \ 1 \ 2
>
> The floating point stack would also be shown if it were being used.
> Other Forths will do the equivalent and perhaps more.
Ok. So the data and floating point stacks are covered.. but what about
the return stack or the control flow stack or the dictionary space the
word references or the other relevant bits of memory it might access?
Of course, custom debugging words could be written to display all of this
information, but my point (in another post regarding Ketman's tutorial)
was that it would be nice if all of this info was already well organized
and displayed for a Forth newbie, who wouldn't be able to write the
relevant debugging words even if he wanted to.
But you appear not to have learned to *always* provide stack comments!
For DOES> words, you should show a stack comment for both parts.
Recommended practice for the stack comment following DOES> is *not* to
include the address that DOES> itself leaves, since the purpose of the
stack comment is to describe usage of the word, and that address isn't
the user's responsibility.
Yuck.
: even-up ( n "name" -- ) 1 + 1 invert and constant ;
--Josh
In Forth that would be:
FOO ( bar baz -- )
and it's plain from a glance at the source that the "foo" function is
receiving "bar" as its first argument and "baz" as its second argument ;-)
>
> But there is no such explicit argument passing in Forth. So you couldn't
> get this information just by glancing at the source of a Forth program
> unless you've memorized the words in each of the definition, or unless
> you look up each word in the documentation.
What? You have seen the explanation a few lines above, and the arguments
are explicit.
>
> And for poorly documented words the pain of figuring out just where their
> input is coming from is that much harder in Forth than in many other
> languages where, again, a simple glance at the source of the function
> will tell you what the function inputs are.
>
Study, study, study.
>> Carbon MacForth's debugging utility is simple but effective. Here is
>> how it can be used:
>>
>> trace on debug on
>> : -ROT ( n1 n2 n3 -- n3 n1 n2 ) ROT ROT ; ok
>>
>> 1 2 3 -rot
>>
>> : -ROT ( 3 ) \ 1 \ 2 \ 3
>> ROT ( 3 ) \ 2 \ 3 \ 1
>> ROT ( 3 ) \ 3 \ 1 \ 2
>> ; ok ( 3 ) \ 3 \ 1 \ 2
>>
>> The floating point stack would also be shown if it were being used.
>> Other Forths will do the equivalent and perhaps more.
>
> Ok. So the data and floating point stacks are covered.. but what about
> the return stack or the control flow stack or the dictionary space the
> word references or the other relevant bits of memory it might access?
The return stack is never (in standard words, the only exception being
DOES>) used to pass information, in the next example its only used
temporary, and within a definition:
: ROT ( n1 n2 n3 -- n2 n3 n1 ) >R SWAP R> SWAP ;
The control flow stack might be the same as the data stack, or altogether
be absent, that's an implementer's choice.
>
> Of course, custom debugging words could be written to display all of this
> information, but my point (in another post regarding Ketman's tutorial)
> was that it would be nice if all of this info was already well organized
> and displayed for a Forth newbie, who wouldn't be able to write the
> relevant debugging words even if he wanted to.
I've written and use a tracer, but information on the returnstack is not
always relevant or can still remembered by me in some instances.
Wait, you're asking for a fairly complex debugging aid, but don't want
to learn how to use those that exist? And object to their complexity?
>>> Some Forth words get what they operate on from what's pushed on the
>>> data stack with the word that comes immediately before them in the
>>> source, others get their input from what the user just typed in the
>>> interpreter, others from words that are typed *after* them.
>>>
>>> It's pretty inconsistent. And you can't tell just by looking at a word
>>> where it'll expect input from or what it'll do with the output. It
>>> doesn't help at all that so many Forth words are monosyllabic or
>>> (worse) just a character or two.
>>
>> As has been mentioned, a good Forth will have a built-in programmer's
>> assist utility for looking up a word's stack effect and a brief
>> description of the word. In Carbon MacForth, for example, typing ROT
>> CTRL-Y will pull up a small window with the following:
>>
>> *********
>> ROT n1 n2 n3 -- n2 n3 n1
>> Rotates the top three stack items the third item is brought to the
>> top.
>> *********
>
> Sure. But in many other languages the arguments to a function are
> explicit rather than implicit. So you'd write something like:
>
> foo( bar, baz ) ;
>
> and it's plain from a glance at the source that the "foo" function is
> receiving "bar" as its first argument and "baz" as its second argument.
The cost of that is preparing the calling sequence in runtime code. In
Forth, the arguments on the stack already exist.
If you need this info, as Doug points out, good Forth implementations
have a way of providing it. In SwiftForth, you can right-click and get
a list of options, one of which is equivalent to typing LOCATE <name>
which will show you the source for <name> and its adjacent documentation.
> But there is no such explicit argument passing in Forth. So you couldn't
> get this information just by glancing at the source of a Forth program
> unless you've memorized the words in each of the definition, or unless
> you look up each word in the documentation.
>
> And for poorly documented words the pain of figuring out just where their
> input is coming from is that much harder in Forth than in many other
> languages where, again, a simple glance at the source of the function
> will tell you what the function inputs are.
When you're writing Forth code you *have* to document it. I agree that
it's more important in Forth than some other languages.
>> Carbon MacForth's debugging utility is simple but effective. Here is
>> how it can be used:
[example snipped]
>>
>> The floating point stack would also be shown if it were being used.
>> Other Forths will do the equivalent and perhaps more.
>
> Ok. So the data and floating point stacks are covered.. but what about
> the return stack or the control flow stack or the dictionary space the
> word references or the other relevant bits of memory it might access?
The control flow stack only exists during compilation. The ability to
monitor other parts of memory is dependent on the implementation's
debugging aids. SwiftForth lets you open a window to monitor either
named locations (e.g. variables) or memory regions.
> Of course, custom debugging words could be written to display all of this
> information, but my point (in another post regarding Ketman's tutorial)
> was that it would be nice if all of this info was already well organized
> and displayed for a Forth newbie, who wouldn't be able to write the
> relevant debugging words even if he wanted to.
Ketman's tutorial isn't an inherent property of assembly language
programming, it's a tool he wrote. Various Forth implementors have
added tools they find helpful. Perhaps you would like to try some and
comment on their appropriateness.
That's the hardest part, right there. For sure.
You hit the nail on the hit. Forth is *implicit* programming. Another
way of describing it is to say that in more conventional programs, you
manage program flow. In Forth, you ALSO have to manage information
flow. You are in charge of the stack. You have to be able to 'see' the
stack in your mind as you are writing code. I still find it much
easier to code with pencil and paper than a keyboard and screen, but
it is getting easier. I just need to write more Forth code.
Mark
I'm guessing you're ok with `CREATE ( "name" -- )`, since it is pretty
simple: it defines the following name to return the address of the
beginning of the free data space. That is, right after you do `CREATE
foo`, `foo` and `HERE` return the same value. Then you can use `ALLOT`
or `,` or `C,` to allocate space for data at that address.
I believe that `DOES>` is confusing mainly because it's a weird syntax.
The basic idea is that, right after you define a word with CREATE, you
can add a "postprocessing" step which does something with the address.
So let's say we have a word `IS-EXTRA-BEHAVIOR ( xt -- )` which sets
the behavior of the most recent definition. Then you could do:
create seventeen 17 , \ return the address where 17 is stored
' @ is-extra-behavior \ now it also fetches the 17
Or you could define arrays:
: [] ( u.index addr.array -- addr.cell ) swap cells + ;
create array 100 cells allot \ array is ( -- addr.array )
' [] is-extra-behavior \ now array is ( u -- addr.cell )
Then instead of defining the extra behavior as its own word and passing
the xt, `DOES>` starts a new definition right there so you can put the
code "inline".
So then the implementation of `DOES>` has to compile code to set the
extra behavior and return from the current definition, and then start a
new definition for the extra behavior.
The traditional implementation exploits the return address (it points
just after the call, so we put the new definition there). So then
`DOES>` could look (roughly) like this:
: (does) r> is-extra-behavior ; \ returns from *caller*
: does> postpone (does) :noname ; immediate
How's that? I skipped all the "fine print", of course, but I hope it
helps you get the basic idea...
--Josh
hmmm ...
: even-up ( n "name" ) 1+ 2/ 2* constant ;
First, what you're describing is the definition of the word "foo", and
not its use. When you see it used it would be something like:
BAR BAZ FOO
or:
BAZ FOO
or even just:
FOO
depending on how many of FOO's arguments are already on the stack.
And from looking at that you have no idea how many arguments FOO is
going to use. You have to look back to the definition of FOO (or
memorize it) to know.
That's not the case in languages where the arguments to a function are
passed explicitly during its use.
Second, what you quoted were stack comments which, though great to have,
aren't always present and honestly aren't present in way too much Forth
code. Usually, you are lucky if you get stack comments.
I recently saw a video made by Samuel Falvo on text processing in Forth,
at the end of which he says,
"If you'll notice, nowhere in my code is there a stack comment.
There's no need for it. The stack is kept so shallow that you can tell
immediately by looking at one particular definition what's on the
stack -- what is needed and what is the result of executing the code."
I beg to differ. Stack comments are essential. Even if the words seem
"obvious" to the author.
He had almost no other comments of any kind in his program either, with
the exception of a couple words of comments that showed which function a
group of words were organized under.
Anyway, I don't mean to pick on Mr. Falvo. I actually appreciate his
video quite a bit for demonstrating what real Forth development is like.
But it also demonstrates how lucky the reader of Forth code is if he
ever sees a stack comment in any of the code he reads. This is quite
unfortunate... especially for a beginner.
>> But there is no such explicit argument passing in Forth. So you
>> couldn't get this information just by glancing at the source of a
>> Forth program unless you've memorized the words in each of the
>> definition, or unless you look up each word in the documentation.
>
> What? You have seen the explanation a few lines above, and the
> arguments are explicit.
As I pointed out above, the explicitness of argument passing in Forth
comes in the definition -- in stack comments, if you're lucky -- not in
the use of the word, and not as a required part of the language.
>> Ok. So the data and floating point stacks are covered.. but what
>> about the return stack or the control flow stack or the dictionary
>> space the word references or the other relevant bits of memory it
>> might access?
>
> The return stack is never (in standard words, the only exception being
> DOES>) used to pass information, in the next example its only used
> temporary, and within a definition:
> : ROT ( n1 n2 n3 -- n2 n3 n1 ) >R SWAP R> SWAP ;
But say I want to understand how that definition works. Ideally, I'd
like to see each of the words that make up the ROT definition manipulate
the return stack in front of my eyes.
This is precisely why I think a tool like the Ketman tutorial would be
a great help for beginners. It would, ideally, make many of the
implicit things that Forth does explicit. It will also hopefully
eliminate any misconceptions that the student has about what's going on,
as what's going on will be plain to see, right in front of their eyes.
You can DO that? Heh. It looks almost like an unbalanced parenthesis
;-).
I guess I don't see the value of this. If there's trouble visualizing,
can't you draw a diagram yourself? It's better than watching passively.
From SICP:[1]
The ability to visualize the consequences of the actions under
consideration is crucial to becoming an expert programmer, just as
it is in any synthetic, creative activity. In becoming an expert
photographer, for example, one must learn how to look at a scene and
know how dark each region will appear on a print for each possible
choice of exposure and development conditions. Only then can one
reason backward, planning framing, lighting, exposure, and
development to obtain the desired effects. So it is with
programming, where we are planning the course of action to be taken
by a process and where we control the process by means of a
program. To become experts, we must learn to visualize the processes
generated by various types of procedures. Only after we have
developed such a skill can we learn to reliably construct programs
that exhibit the desired behavior.
So I think it's best to practice reading such code without watching
an animation.
[1] http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-11.html#%_sec_1.2
First I will say that you seem to be expecting Forth to be something
in particular. Forth is not like the other languages you have
learned. I can't say why the people who use Forth use it the way they
do. But I can tell you that it does work. There are some aspects of
Forth that will work very well if you go with the flow rather than
bucking the trend. Let go of your emotional attachment to what you
know and allow the Forth to guide you.
On Jun 11, 5:51 pm, stavrogin <usenet.20.blacksil...@spamgourmet.com>
wrote:
> On Sat, 11 Jun 2011 21:31:26 +0200, Coos Haak wrote:
>
> > Op 11 Jun 2011 17:25:26 GMT schreef stavrogin:
>
> >> Sure. But in many other languages the arguments to a function are
> >> explicit rather than implicit. So you'd write something like:
>
> >> foo( bar, baz ) ;
>
> >> and it's plain from a glance at the source that the "foo" function is
> >> receiving "bar" as its first argument and "baz" as its second
> >> argument.
>
> > In Forth that would be: FOO ( bar baz -- ) and it's plain from a
> > glance at the source that the "foo" function is receiving "bar" as its
> > first argument and "baz" as its second argument ;-)
>
> First, what you're describing is the definition of the word "foo", and
> not its use. When you see it used it would be something like:
>
> BAR BAZ FOO
>
> or:
>
> BAZ FOO
>
> or even just:
>
> FOO
>
> depending on how many of FOO's arguments are already on the stack.
>
> And from looking at that you have no idea how many arguments FOO is
> going to use. You have to look back to the definition of FOO (or
> memorize it) to know.
Yes, using the stack is one of Forth's biggest drawbacks to those who
are new to it, especially if you have an existing methodology you are
used to. This is not the barrier it seems to be. What can be a
barrier is learning about new words that are not readily documented
other than in the source. But that is pretty much like any language
that I have seen. Tons of C code is not documented at all, even in
the source code. You have to reverse engineer it.
Of course that should not be the case with a tutorial.
> That's not the case in languages where the arguments to a function are
> passed explicitly during its use.
The arguments to a function are only a small part of understanding
it. Without a full description of a function you are left reading the
source code to understand it anyway.
> Second, what you quoted were stack comments which, though great to have,
> aren't always present and honestly aren't present in way too much Forth
> code. Usually, you are lucky if you get stack comments.
Yes, like in C code not having comments. Life sucks and then you
die. Or perhaps I was influenced too much by the assistant to my
doctor who when I mentioned some of the health issues I'm having, told
me, "Live is a slow, downward spiral". Not much of a bedside
manner...
But in reality, isn't this the same in most languages? This is the
programmers, not the langugae.
> I recently saw a video made by Samuel Falvo on text processing in Forth,
> at the end of which he says,
>
> "If you'll notice, nowhere in my code is there a stack comment.
> There's no need for it. The stack is kept so shallow that you can tell
> immediately by looking at one particular definition what's on the
> stack -- what is needed and what is the result of executing the code."
>
> I beg to differ. Stack comments are essential. Even if the words seem
> "obvious" to the author.
You missed his point. His point is not about stack comments being
important. He is saying that good programming style tells you to not
use the stack deeply. Some hardware implementations only give you 8
levels on the return stack and likely the same on the data stack. Not
a lot to remember there... The point is to code in a way that lets
you "see" what the code is doing rather than having to work your way
through it. I can't say I am good at that, but I've coded enough
Forth to see this is an important principle.
> He had almost no other comments of any kind in his program either, with
> the exception of a couple words of comments that showed which function a
> group of words were organized under.
>
> Anyway, I don't mean to pick on Mr. Falvo. I actually appreciate his
> video quite a bit for demonstrating what real Forth development is like.
> But it also demonstrates how lucky the reader of Forth code is if he
> ever sees a stack comment in any of the code he reads. This is quite
> unfortunate... especially for a beginner.
>
> >> But there is no such explicit argument passing in Forth. So you
> >> couldn't get this information just by glancing at the source of a
> >> Forth program unless you've memorized the words in each of the
> >> definition, or unless you look up each word in the documentation.
>
> > What? You have seen the explanation a few lines above, and the
> > arguments are explicit.
>
> As I pointed out above, the explicitness of argument passing in Forth
> comes in the definition -- in stack comments, if you're lucky -- not in
> the use of the word, and not as a required part of the language.
Yep, there is not much that the language forces on you at all. That
is an issue with newbies who expect a language to "enforce" good
practices on them. It is a benefit to programmers who know how to use
that freedom without it hurting them. Sort of like using a sharp
knife. It will do what you want much better, but is easier to cut you
if you don't know how to use it safely.
> >> Ok. So the data and floating point stacks are covered.. but what
> >> about the return stack or the control flow stack or the dictionary
> >> space the word references or the other relevant bits of memory it
> >> might access?
>
> > The return stack is never (in standard words, the only exception being
> > DOES>) used to pass information, in the next example its only used
> > temporary, and within a definition:
> > : ROT ( n1 n2 n3 -- n2 n3 n1 ) >R SWAP R> SWAP ;
>
> But say I want to understand how that definition works. Ideally, I'd
> like to see each of the words that make up the ROT definition manipulate
> the return stack in front of my eyes.
Can't you get that by reading their definition, either in code or in
the book? I'm pretty sure >R R> and SWAP are all covered in Starting
Forth or any other novice text.
Jeff Fox is no longer with us. But I learned a huge amount about
Forth and about approaching new ideas from him. He would write things
that sounded absurd, either absurdly simple or absurdly wrong... but
when I gave them their proper thought AND let go of my believes in the
conflicting things I had learned, I realized how true they were.
Probably the best example is his response to people wanting detailed
info to debug stack problems, "You can't count". Yes, making sure
your definitions don't have stack effect errors is just a matter of
knowing how to count! So you really shouldn't need special debuggers
to help you single step through code to find a stack over flow or
under flow. All you need to do is count when you write AND TEST the
word.
My suggestion to you would be to stop focusing on how Foth is
different from what you are used to. Instead try to learn how other
use Forth and how they get things done with it.
Rick
I suppose this same argument has been made against any tool that helps
people do something they could have otherwise done themselves.
Look, even if these small handful of things that could be easily
visualized by a program are visualized for the beginner who's learning
Forth, there'll still be plenty of things left for him to visualize, such
as the interactions between all the various words in the system, what
he's trying to achieve, why things might be going wrong, etc.
I don't think we have to worry about the art of visualization dying out
just because a tool to help beginners becomes available.
I'm not expecting Forth to be like other languages. I'm just pointing
out why I'm finding it difficult compared to other languages.
I know there are advantages to doing things the way Forth does them. If
I didn't know that, I wouldn't bother trying to learn Forth at all.
> Tons of C code is not documented at all, even in the source code.
> You have to reverse engineer it.
I am not holding up C as a model language. And, naturally, poor code
and poorly documented code can be written in any language.
However, since so much is implicit in Forth, I find undocumented Forth
code
more difficult to read than languages which are more explicit.
I'm sure reading Forth will get easier with experience, but it's
certainly not easy for me now. I have to struggle through each word
definition, and this struggle is what I wanted to point out who claim
that "Forth is so simple you'd have to be a vegetable not to understand
it".
> The arguments to a function are only a small part of understanding it.
> Without a full description of a function you are left reading the source
> code to understand it anyway.
I find that I can get a pretty good feel for what a program is doing
from reading (in context) descriptive function names with descriptive
arguments.
This is much harder when you see something like:
xcv e2g z x(8
What did what to what here?
Of course, reading something like this is much easier if the words in
question are standard, if the names are meaningful, and/or if you
already know what they do. But even then you're going to have to
somehow divine what's on the stack(s) at that point in the program.
As always, good documentation should go a long way towards compensating
for this lack of information.
> You missed his point. His point is not about stack comments being
> important.
If he thought they were important, he would have put them in. But his
code didn't have a single stack comment. Clearly, he didn't think his
code needed them, and he said as much.
> He is saying that good programming style tells you to not
> use the stack deeply.
I'm definitely not disagreeing with that, and see the virtue of keeping
a shallow stack.
> Yep, there is not much that the language forces on you at all. That is
> an issue with newbies who expect a language to "enforce" good practices
> on them. It is a benefit to programmers who know how to use that
> freedom without it hurting them. Sort of like using a sharp knife. It
> will do what you want much better, but is easier to cut you if you don't
> know how to use it safely.
Well, I can sympathize with that approach, to an extent. For instance,
I find Python's forcing of meaningful whitespace on its programmers
really annoying. I am perfectly capable of properly indenting my code
myself, to my own liking, and also capable of running other people's
code through a beautifier/indenter, should I need it. So that enforced
convention does feel like being to wear training wheels, and I kind of
resent it.
So I can kind of see the advantages of Forth's freeing the programmer
from needing to use explicit arguments. Sometimes it is convenient.
But most of the time I just find it makes for more difficulty in
puzzling out just what the @#$% is going on. Good comments help, but
with enough comments, you might as well be passing arguments explicitly
anyway and at least get the benefit of some checks on them that the
compiler can give you.
Fortunately, Forth compensates for some of this implicit information
hiding with some other features.
Anyway, I don't mean to turn this to an flamewar about the virtues of
Forth. Like I said, I'm convinced enough of them to continue learning
it. But I did want to note the difficulty I was having with parts of
it, and the reasons for that difficulty.
>> >> Ok. So the data and floating point stacks are covered.. but what
>> >> about the return stack or the control flow stack or the dictionary
>> >> space the word references or the other relevant bits of memory it
>> >> might access?
>>
>> > The return stack is never (in standard words, the only exception
>> > being DOES>) used to pass information, in the next example its only
>> > used temporary, and within a definition:
>> > : ROT ( n1 n2 n3 -- n2 n3 n1 ) >R SWAP R> SWAP ;
>>
>> But say I want to understand how that definition works. Ideally, I'd
>> like to see each of the words that make up the ROT definition
>> manipulate the return stack in front of my eyes.
>
> Can't you get that by reading their definition, either in code or in the
> book? I'm pretty sure >R R> and SWAP are all covered in Starting Forth
> or any other novice text.
Sure. But the books won't tell me what is being moved to/from the
return stack, or what is being swapped. I'd like to be able to see
that.
Of course, this example is incredibly trivial, and the usefulness of
such a visualization facility would not be very great for this
particular example. But the more complex the word gets, the more useful
the visualization will be. It will also be more useful for words that
you're not very familiar with yet.
Consider the case of visualizing a sort. Don't you think it would be
useful to see the items being placed in order while the sort is running?
Or see them not being correctly placed in order when there's a bug in
your code?
There are actually some nice visualizations of sorts (some using living
people) on youtube. I find them pretty useful for understanding those
algorithms.. and I'm sure visualization of what's going on on the Forth
stacks and in memory could be similarly helpful.. especially for
beginners.
> Jeff Fox is no longer with us. But I learned a huge amount about Forth
> and about approaching new ideas from him. He would write things that
> sounded absurd, either absurdly simple or absurdly wrong... but when I
> gave them their proper thought AND let go of my believes in the
> conflicting things I had learned, I realized how true they were.
> Probably the best example is his response to people wanting detailed
> info to debug stack problems, "You can't count". Yes, making sure your
> definitions don't have stack effect errors is just a matter of knowing
> how to count! So you really shouldn't need special debuggers to help
> you single step through code to find a stack over flow or under flow.
> All you need to do is count when you write AND TEST the word.
I don't expect the tool I'm proposing to replace counting or testing.
You're still going to need to do that sort of thing, but it should make
it easier.
It's kind of a bit like a calculator. Calculators haven't replaced the
need for humans to do math. But it makes doing some trivial math
problems easier.. and let people concentrate on more important and
interesting math, while leaving the trivial details to the computer.
Unfortunately, the calculator analogy is imperfect, because a calculator
doesn't really help you visualize anything. In fact, it often does the
opposite: depriving the user of the insight they'd otherwise get by
visualizing the problem. The tool I'm describing would do the opposite
and actually help you to visualize what's going on. And it would also
provide a check for you in case your own visualization and expectations
of what was going to happen were wrong.
The analogy of a flight simulator would probably be a better one. Sure,
you could imagine what flying an airplane is like, or actually try to do
it in a simulator, where you could manipulate the controls and
immediately see the results of your actions on the instruments and other
aspects of flight that the simulator visualizes.
Some might argue that the pilot should calculate all the different
things the instruments tell him in his head as he flies. But the pilot
has much more important things to do.. and a student pilot would be
completely overwhelmed if he had to do that while actually flying the
plane. Of course it's nice to be able to do so when one doesn't have
access to such visualization tools, but it's hard to deny their
usefulness.
I started programming in Forth in 1971, and was a full-time user of
Forth or manager of Forth projects (including teams of up to 30
programmers) till I retired a few years ago.
I couldn't disagree with Mr. Falvo more strongly. From day 1 at FORTH,
Inc. programmers have been required to use stack comments for every
definition, and provide usage info where appropriate. We also follow
specific coding and naming conventions (published as appendices to my
books). As a result, it is generally impossible to tell who wrote which
code, and everyone can read all the code produced in the company (and by
others who follow our coding conventions) easily.
In fact, when I am teaching, I encourage my students to design the word
and put its stack comment in even before writing the code. It helps to
write the code if you have the reminder of what's on the stack in front
of you!
It is true that many definitions are short and the stack tends to remain
shallow. So, if you have to, you can figure out what stack arguments
are needed by a particular definition. But that is far from universally
true, and in any case, it's much quicker to look at the stack comment
than to analyze code, and time is money.
...
>>
>> The return stack is never (in standard words, the only exception being
>> DOES>) used to pass information, in the next example its only used
>> temporary, and within a definition:
>> : ROT ( n1 n2 n3 -- n2 n3 n1 )>R SWAP R> SWAP ;
>
> But say I want to understand how that definition works. Ideally, I'd
> like to see each of the words that make up the ROT definition manipulate
> the return stack in front of my eyes.
The problem here is that this definition may model the behavior of ROT,
but in most systems it is written in code and doesn't use the return
stack. And in modern compile-to-code implementations the code may get
optimized quite differently -- the value being saved on the return stack
may be in a register, or managed quite differently.
This is great advice. And I must say that the source included with
SwiftForth is some of the most easily readable that I've seen. Though I
have yet to dig deep in to it, as most of it is far too advanced for me.
But even without understanding it in depth, it's easy to see that it's
well factored, with stack comments everywhere, and a fair amount of
documentation (though not as exhaustively documented as I, as a
complete beginner, would prefer).
> In fact, when I am teaching, I encourage my students to design the word
> and put its stack comment in even before writing the code. It helps to
> write the code if you have the reminder of what's on the stack in front
> of you!
I try to do that, and more. I will also often write all of the stack
effects of the words I use right next to them (with one word per column)
using some example values. This really helps me to understand
what's going on tremendously.
I've read others on this newsgroup recommend doing the same, but for
some reason they advise erasing those comments afterwards, and trying
to fit the whole definition back on to one line.
Sure, it looks neater afterwards, and adheres to the common injunction
to keep definitions down to 3 or 4 lines. But then you've deprived the
next person who reads your code of the benefit of the documentation you
just came up with.
> It is true that many definitions are short and the stack tends to remain
> shallow. So, if you have to, you can figure out what stack arguments
> are needed by a particular definition. But that is far from universally
> true, and in any case, it's much quicker to look at the stack comment
> than to analyze code, and time is money.
I absolutely agree with this too. And not only does such documentation
save you time, but when (without it) you are forced to carefully read
each little bit of code to understand it, you can easily miss the forest
for the trees. It's far too easy to get bogged down in the details while
missing the big picture.
Conversely, if the big picture is documented, you can always dig down in
to the nitty-gritty details should you want/need to while always being
able to get a bird's eye view at a glance.
>> But say I want to understand how that definition works. Ideally, I'd
>> like to see each of the words that make up the ROT definition
>> manipulate the return stack in front of my eyes.
>
> The problem here is that this definition may model the behavior of ROT,
> but in most systems it is written in code and doesn't use the return
> stack. And in modern compile-to-code implementations the code may get
> optimized quite differently -- the value being saved on the return stack
> may be in a register, or managed quite differently.
Well, I suppose that for those words which are written in assembly, an
assembly language tool like Ketman's would be more appropriate than the
Forth tool I'm advocating. But those portions of the program that could
be visualized under the Forth VM should be.
It's really just a matter of wanting to see the effects of each word as
they happen. Yes, I could look them up in the manual. Yes, maybe I given
their definition and a decent knowledge of Forth, I could reason them
out for myself. Yes, maybe I could just read the source for the Forth
interpreter or use the disassembly or debugging features of Forth to get
at what's going on.
But using the Forth equivalent of Ketman's would (ideally) give you all
of that information instantly as it happens, and in a very nicely
organized manner. I really can't see any plausible disadvantage to
using such a tool, were it available.
Forth is extremely explicit (hmm, that word is not intended to sound
naughty). Saying Forth words receive stack args implicitly uses the
word "implicit" differently from how the Python Zen used it.
For example, in Perl or Python, you could have a character string whose
contents happen to all be digits:
$a = "52"; # perl
a = "52" # python
In Perl, if you add 3 to $a, it will convert the string to a number
and give you 55. That is an implicit conversion. Python will instead
throw a type error. If you want to convert "52" to a number you
have to do it explicitly:
print float("52") + 3
In this sense Forth is as explicit as anything can be. Nothing happens
automatically. You should probably even stop thinking of Forth as a
high-level language. It's much closer to being an assembly language.
Classic Forth implementations are much more like assemblers than
compilers. They make a single pass through the input code, translating
the words to target code (traditionally threaded) as they go. Then they
back-patch a few addresses for the jump targets of IF statements and
that's it. There's a few fixed-sized buffers like the parse area, a few
variables like HERE, one peristent data structure (the dictionary,
traditionally implemented as a linked list of words) and a little bit of
stack traffic as compiling progresses. It's fiendishly clever but at
the same time completely low tech. Fancier implementations today use
real compilation techniques to generate optimized machine code, but the
semantics are the same. If you've already done some assembly language
programming on any machine, then Forth should seem completely natural.
You mentioned stack comments an were also asking earlier about PICK. It
occurs to me that stack comments are basically unenforced type
declarations, and Forth programmers actually tend to program in a typed
style even though the language is untyped. The thing about PICK (unless
its parameter is a fixed literal, like 3 PICK) is that once you use it,
it becomes much harder to reason about what types are on the stack. So
that may be why Forthers don't like it.
Leo Brodie's book "Thinking Forth" talks about stuff like this. You
should probably read it. I found it much more interesting than
"Starting Forth".
> [other post] I find Python's forcing of meaningful whitespace on its
> programmers really annoying. I am perfectly capable of properly
> indenting my code myself...
You'll get used to it if you code in Python for a while. One could
equally say "I find C's forcing of curly braces for statement grouping
really annoying. I am perfectly capable of properly indenting my code
myself, and the indentation shows the code's structure, so the compiler
should be able to figure it out from the indentation without braces."
That is what Python does: figures out the code structure from your
indentation instead of forcing you to use other delimeters.
Usually, you need to locate a book or webpage with visual diagrams and the
Forth words with stack comments. E.g., ROT ( a b c -- b c a ) and then
there will be a visual diagram showing the reordering, but you should be
able to figure it out from the comments. The stack is just like a stack of
cards or coins. The stack comments are setup like so:
( stack_before_operation -- stack_after_operation )
The rightmost item in each list is the top-of-stack. So, ROT removes the
third item 'a' out from the stack pushing 'b' and 'c' down, and then pushing
'a' on top. Basically, it shows just the changes to the top of the data or
parameter stack. For the return stack, they sometimes place an R: or
somesuch to indicate that the item is on a different stack.
E.g., if you had a stack of coins: nickel, dime, quarter, penny, with the
penny on top and nickel on the bottom, ROT would yield: nickel quarter,
penny, dime, with the dime on top and nickel on the bottom. If you're a
cardcheat, you've 'popped' the third card, i.e., Ace, to the top.
Let's take this common definition for ROT:
>R SWAP R> SWAP
The >R and R> takes one item and temporarily stores it on the return stack.
c <-- TOS top of stack
b
a
After >R :
b R:c
a
That moves c to the return stack, for temporary storage. b is the top of
the data stack, c is the top of the return stack.
After SWAP:
a R:c
b
After R> :
c
a
b
After SWAP:
a
c
b
So, we started with a b c and ended with b c a , which is ROT.
This may help. It doesn't animate. But, it tells you the Forth words
needed to produce a certain stack manipulation:
Forth Wizard
http://forpost.sourceforge.net/forthwiz.html
E.g., for ROT, you'd hit clear, enter: a b c without quotes, with spaces
into the left stack description area, then enter: b c a without quotes, with
spaces. Then, click 'solve', and then 'more' repeatedly. It'll emit the
equivalent operations:
rot
swap rot rot swap
>r swap r> swap
dup >r rot r> drop
swap rot >r swap r>
over >r rot r> drop
no solutions
Of course, defining ROT in terms of ROT is pointless ... Other words will
produce useful sequences.
Typical stack comments for Forth stack words:
drop ( a -- )
dup ( a -- a a )
swap ( a b -- b a )
over ( a b -- a b a )
rot ( a b c -- b c a )
-rot ( a b c -- c a b )
nip ( a b -- b )
tuck ( a b -- b a b )
3 roll ( a b c d -- b c d a )
3 pick ( a b c d -- a b c d a )
drip ( a b -- b b )
dip ( a b -- a a )
nup ( a b -- a a b )
take ( a b c -- b a )
2drop ( a b --)
2dup ( a b -- a b a b )
2swap ( a b c d -- c d a b )
2over ( a b c d -- a b c d a b )
2rot ( a b c d e f -- c d e f a b )
-2rot ( a b c d e f -- e f a b c d )
2nip ( a b c d -- c d )
2tuck ( a b c d -- c d a b c d )
HTH,
Rod Pemberton
Thank you! There is, of course, considerably more documentation on
SwiftForth in the form of the SwiftForth Reference Manual in the \doc
directory, plus the Forth Programmer's Handbook for generic Forth
issues. If you haven't done so, be sure to read Section 2 of the
SwiftForth Reference Manual on programmer aids.
>> In fact, when I am teaching, I encourage my students to design the word
>> and put its stack comment in even before writing the code. It helps to
>> write the code if you have the reminder of what's on the stack in front
>> of you!
>
> I try to do that, and more. I will also often write all of the stack
> effects of the words I use right next to them (with one word per column)
> using some example values. This really helps me to understand
> what's going on tremendously.
>
> I've read others on this newsgroup recommend doing the same, but for
> some reason they advise erasing those comments afterwards, and trying
> to fit the whole definition back on to one line.
>
> Sure, it looks neater afterwards, and adheres to the common injunction
> to keep definitions down to 3 or 4 lines. But then you've deprived the
> next person who reads your code of the benefit of the documentation you
> just came up with.
I think that is a very useful practice for beginners, and I'm happy that
you find it helpful. I'm not sure that I'd go so far as to recommend
actually removing your extra comments after the fact, but once you
advance past a certain point I think you'll find the practice is more
trouble than it's worth, and it's easier to read horizontal code than
vertical code.
After
all,
we
don't
write
prose
vertically.
I wasn't accusing Forth of doing implicit type conversion or anything
of the sort.
But figuring out where a given word gets its arguments can't be done
just by looking at the place in the source where the word is used.
Rather, you have to look at the word's definition and/or the
documentation. That's what I mean by implicit.
What a Forth word does is hidden within its definition,
rather than being more out in the open as with most other languages,
where at least you can see precisely which arguments are being
passed to the function.
The situation is made even worse in Forth because so many words
tend to be given either completely meaningless or extremely short
names, and worse still by the rarity of giving any sort of names
to a word's arguments (except maybe in the documentation of its
definition).
In most other languages, again, the arguments passed on to a function
have named arguments with (hopefully) meaningful names. That's what I
mean by explicit.
> You should probably even stop thinking of Forth as a high-level
> language. It's much closer to being an assembly language. Classic
> Forth implementations are much more like assemblers than compilers.
Yes, and reading assembly code can also be an exercise in frustration.
> You mentioned stack comments an were also asking earlier about PICK.
> It occurs to me that stack comments are basically unenforced type
> declarations, and Forth programmers actually tend to program in a
> typed style even though the language is untyped. The thing about PICK
> (unless its parameter is a fixed literal, like 3 PICK) is that once
> you use it, it becomes much harder to reason about what types are on
> the stack. So that may be why Forthers don't like it.
Actually, it wasn't me who mentioned PICK. The only words I mentioned
were CREATE, DOES>, ROT, and SWAP. I did mention local variables,
though. And I suppose what you say about PICK could be applied
to locals as well.
I suppose there is something to wanting to stay "close to the machine",
and "stay sharp" by doing all the hard work yourself.
When you need to translate decimal to binary, you do it yourself.
If you want to eat a bowl of spaghetti, you grow the wheat yourself,
harvest it yourself, mill the grain yourself, knead the dough
yourself, etc..
I can see the advantage of that. You can really appreciate your food
when you do that, you can learn a lot, and keep your agricultural and
baking skills sharp.
Similarly, with programming there are advantages to doing everything at
the lowest level possible.
But sometimes you just want to get the job done.. and get it done in the
cleanest, fastest, and most convenient way possible.
Maybe Forth is the wrong language for that. But I have heard some say
that Forth is the language you can shape to your needs, and you don't
have to shape yourself to the language.
You're supposed to be able to mold the language to your problem domain
and work in the language of your problem.
Perhaps they were wrong.
> Leo Brodie's book "Thinking Forth" talks about stuff like this. You
> should probably read it. I found it much more interesting than
> "Starting Forth".
Yeah, I mean to. But right now I'm more interested in the practical
aspects of learning to actually program in Forth rather than
the philosophical issues surround The Forth Way (though I admit to being
kind of sidetracked from my goal by this conversation).
The dynamic memory display in SwiftForth is useful for this, in
conjunction with the stepping debugger.
That is in fact what I'm doing. And for the simple things, such as ROT,
that's adequate. But for more complex definitions it can be painful.
The pain increases with the number of words in the definition. And at
any point my own visualization of the what's going on with the various
stacks (not to mention memory) could be wrong.
Books and webpages also tend to only cover the standard words, not some
arbitrary definition I or someone else have cooked up. And even for
those definitions that books and webpages cover, their explanations
could be inadequate or incomplete. And even when they are complete,
they're not necessarily going to show you what happens to the specific
data that's on your stack or in memory.
To give the most basic example, a description of the + word will tell
you that an addition is going to be performed on the two words at the
top of the data stack, but it won't show you that:
2345 3456 +
will result in 5801. And here it's not really a matter of me not
understanding addition. But I just want the computer to do the addition
for me and show me the result, along with where it got the arguments and
where it's sending them to.
Yes, there are other ways to figure this out, without relying on a
computer to do the work for you. You could dig out the manual, memorize
the word and stack effects, poke around the stack yourself, turn on
the trace or debugging features of interpreter, etc.. but it's really
not the same as seeing what's being done to what and what the result is
ala Ketman's tutorial.
And, as I mentioned above, the usefulness of this sort of thing
increases with the complexity of the definition you're examining, and
with the complexity of the words that definition is made up of.
Clearly, visualizing simple addition has limited usefulness (though
still quite useful, considering the popularity of calculators), but
there are plenty of other words in Forth that perform more complex
actions on a large variety of things, for which such visualization would
be even more useful.. especially in a complex definition, and especially
for a beginner.
> This may help. It doesn't animate. But, it tells you the Forth words
> needed to produce a certain stack manipulation:
>
> Forth Wizard
> http://forpost.sourceforge.net/forthwiz.html
That looks useful. But, again, not really what I'm looking for in a
Forth analog to Ketman's tutorial, which would present you with immediate
interpretation of the actual words in your program, show you where the
arguments of each word is coming from and the result is going to,
and display the result in an organized way.
It's really not about needing to see the stack effects animated, but
about pointing out what is being done to what and where things are going
as they happen, and also seeing the results as they happen.
I'd say the words normally communicate through a big global variable
called "the stack". Yes that causes some issues that are managed mostly
by following consistent practices about what types of stack effects
words should have. Again, "Thinking Forth" is probably more helpful
than looking for lots of stack comments.
You might look at StrongForth:
http://home.vrweb.de/stephan.becher/forth/
It's like ANS Forth but the stack comments are mandatory and their
correctness is enforced by the compiler. It has not gotten much
traction with actual Forth programmers though.
> You're supposed to be able to mold the language to your problem domain
> and work in the language of your problem.
Well, Forth is a 1960's-1970's language that uses the limited hardware
resources typical of that era in a really brilliant way. If that's not
what your problem domain involves, Forth might not be that great a match
for your purposes. These days if you want to write an EDSL for
something other than a microcontroller, you are probably better off with
Lisp or Haskell (depending on whether you want compiler-supplied static
typing), even though both of those require much more powerful hardware
than Forth does. Forth is of course still interesting as a pattern of
thought, source of ideas, etc.
Anyway, Forth isn't rocket science. There's a couple dozen important
words like DUP, SWAP, basic arithmetic, etc. whose meanings are obvious
and easy to remember. Once in a while you might need something more
obscure that takes a trip to the manual. It's just like anything else.
> Yeah, I mean to. But right now I'm more interested in the practical
> aspects of learning to actually program in Forth rather than
> the philosophical issues surround The Forth Way
Some take the view that the philosophy is inseparable from the practical
aspects.
If I ever get to be as fluent in Forth as I am in English, I'll be a very
happy man.
Mostly. But not uniformly or consistently. Some words do while others
don't. And you can't tell just by looking at them which is which. And
even for those words that do communicate via the stack, there's no way
to tell by looking at them how many arguments they take or which
argument belongs where. You have to memorize where they get their
arguments, or look them up.
> You might look at StrongForth:
>
> http://home.vrweb.de/stephan.becher/forth/
>
> It's like ANS Forth but the stack comments are mandatory and their
> correctness is enforced by the compiler. It has not gotten much
> traction with actual Forth programmers though.
It looks interesting. But my main problem is that most documentation
and ready-made code as been written for ANS Forth. So that's really
what I'm stuck with, unless I want to write everything from scratch in
StrongForth.
It might be useful for some small projects, though, where I am writing
pretty much everything I need from scratch anyway.
> Anyway, Forth isn't rocket science. There's a couple dozen important
> words like DUP, SWAP, basic arithmetic, etc. whose meanings are obvious
> and easy to remember. Once in a while you might need something more
> obscure that takes a trip to the manual. It's just like anything else.
I don't mean to imply that it is rocket science. But it's not all
as obvious as DUP and SWAP either. Just take a look at most of the code
posted to this newsgroup.
There are really not many complex actions in Forth. The most striking
thing about it is the brutal simplicity of everything it does, at least
at the traditional implementation level. To the extent there are subtle
ideas, I don't think low-level animations will help much. It will
probably take some head-scratching. There is a similar issue in Haskell
about a difficult topic called "Monads":
http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/
"Forth animation" and "Monad tutorial" sound like they may work out
about the same way.
There is an all-Javascript ANS Forth implemetantion here:
http://forthfreak.net/jsforth.js
You can run it in a browser here:
http://forthfreak.net/jsforth80x25.html
The JS code looks interesting and is probably easier to read than an asm
version.
A very very interesting discussion. I wish Jeff were around to read
it.
Forth as an assembler type language is a useful analogy, at least to
me. I often describe it as assembly on steroids.
When writing assembly code, one tends to document as much as one can.
I personally, am a prodigious documenter of assembly code... I'm kind
of siding with Stavrogin here! Here's some genuine assembly code with
no comments, taken from my Forth system:
_cmovf mov *stack,r2
jeq cmvext
mov @-2(stack),r1
mov @-4(stack),r0
dec r2
a r2,r1
a r2,r0
inc r2
cmvflp movb *r0,*r1
dec r0
dec r1
dec r2
jne cmvflp
cmvext ai stack,-6
b @retB0
Anyone care to venture what it does? Probably not. The labels may give
you a clue. Perhaps it's CMOVE? The labels sort of indicate that it
might be, _cmovf and the like.
And Forth code is often *exactly* like that. One can get a clue, an
incling about what some code is doing. But often not understand it
fully.
Here's the code with comments:
;[ CMOVE> ( addr1 addr2 count -- )
; Move the count bytes at address addr1 to addr2. The move begins by
moving the
; byte at addr1 plus count minus 1 to addr2 plus count minus 1 and
proceeds to
; successively lower addresses for count bytes.
; If count is zero nothing is moved.
; (Useful for sliding a string towards higher addresses)
_cmovf mov *stack,r2 ; count
jeq cmvext ; exit if count=0
mov @-2(stack),r1 ; addr 2
mov @-4(stack),r0 ; addr 1
dec r2 ; count-1
a r2,r1 ; addr2=addr2+count-1
a r2,r0 ; addr1=addr1+count-1
inc r2 ; restore count
cmvflp movb *r0,*r1 ; move a byte
dec r0 ; decrement addr 1
dec r1 ; decrement addr 2
dec r2 ; decrement count
jne cmvflp ; loop if not finished
cmvext ai stack,-6 ; pop 3 parameters off the stack
b @retB0 ; return to caller
;]
And I think Forth words (perhaps not top-level words but certainly the
lower down, nuts-and-bolts words) should be documented to the same
level.
I often write out my Forth words in this way. I think if you are using
a file based Forth system, it is a very very good idea to write your
code vertically and comment every line. There's no cost to prevent you
doing so, except for a larger source file. If people don't want to
read the comments, don't read them. If you are using blocks, you're
stuck, and you will have to factor factor factor to get readable code.
For example:
: ECHO-LINE WithInputBuffer GetAWord WordFound? IF SetLED On
SendToSerialPort THEN SetLED Off ;
That is perfectly valid, highly readable Forth code. Reads more like
English than code. But it's highly factored. One could possibly see,
in the minds eye, that WithInputBuffer probably returns some sort of
pointer to the input buffer (whatever that is) which GetAWord
consumes. It looks like GetAWord must leave a pointer to the word
found (perhaps an address/length pair, or maybe it sets globals?) and
*possibly* a boolean for WordFound? Or, maybe WordFound? checks the
length for greater than 0? And that's the point with Forth, which
*can* make it hard. The real details, the parts that an interested
third party would want to see to debug it two years after his
predecessor left are hidden elsewhere. It's *implicit*. However, in
fairness to Forth, factoring is factoring. It's not unique to Forth:
Sub echoLine(strInputBuffer)
If WordFound?(GetAWord(InputBuffer)) Then
Led.On
SendToSerialPort
EndIf
Led.Off
End Sub
That's valid factored VB.Net. Bloody horrible if you ask me. I prefer
the Forth version.
You will find deeper levels of factoring in Forth, because it is
definately easier to write code when you factor.
And that brings me on to another point. Code can be over factored.
Ever tried to SEE a word in Gforth? Sheesh... You never get to the
bottom! However, highly factored code does make debugging much easier.
One could imagine writing of those Forth words above in isolation, and
testing them. The comments in the code for each of the colon
definitions (WithInputBuffer etc) would be verbose, and could be used
later for the applications documentation set. Then, when all the above
words are written you have a nice lexicon of words, which makes ECHO-
LINE utterly trivial to write. This is where Forth can shine. But
yeah, I feel your pain. *Writing* Forth? Simple! Reading it back, not
so simple! But factoring helps.
When I'm writing Forth code, I normally write it in a notebook first,
with notes. Here's some code I wrote just the other day. It's specific
to my system, I think the use of BSAVE for overlays is long gone, but
it illustrates the point:
: LOAD-SAMPLES ( startblock --)
HERE ( save HERE to the stack)
LATEST @ ( save LATEST to the stack)
ROT ( get startblock to top of stack)
BLOAD ( load the data)
( when BLOAD exits it has the next block number)
( on the stack, which is where the data for high)
( memory is, so just use it...)
BLOAD ( load high memory data)
DROP ( drop the block number left by BLOAD)
LATEST ! ( restore LATEST)
H ! ( restore HERE via variable H)
;
Written horizontally then, it's:
: LOAD-SAMPLES ( startblock --)
HERE LATEST @ ROT BLOAD BLOAD DROP LATEST ! H ! ;
The best one can do horizontally is use spaces to separate phrases.
You've just got to hope that:
a) The reader is experienced enough to be able to hang on and
understand your code
b) You are a good enough coder that your code gives the reader a
fighting chance ;-)
Commenting code written horizontally has always been an issue,
particularly in a block based system, which is why the somewhat kludgy
notion of shadow blocks exist.
Regards
Mark
Respectfully, on-screen visualisation isn't going to help much for
complex definitions though, because they will tend to highly factored,
so God knows what is going on under the covers. Imagine, for example,
trying to visualise EXPECT which uses TIB, #TIB, & >IN, reads the
keyboard with KEY and updates the screen with EMIT, where EMIT
(assuming it hasn't been vectored to redirect its output to a file)
has to update the XY cursor position and zero X at the end of a line,
increasing Y, and calling the screen scroll routine if you are the
bottom of the screen.
How would visualising all of that on, say, the data-stack help you?
You'd have some nice data set up on the stack, tab over to EXPECT,
then maybe you type a line of text and press enter. Then a flurry of
activity happens, and you are left a single item on the stack - the
number of characters received. What does that tell you that you can't
get from the simple comment:
EXPECT ( address length -- receivedLength )
Reads length characters of input from the current input device,
storing them starting at address address, and stopping when a carriage
return or an implementation specific maximum number of characters has
been received. Upon completion, the number of characters actually
received and stored is pushed to the stack. The terminating carriage
return is not stored in the buffer, nor is it included in
receivedLength.
In fact, if you typed HELLO WORLD! at the cursor prompt when EXPECT
ran, you'd probably have to look up the definition of EXPECT to
understand the significance of the 12 that came back on the stack! ;-)
Mark
This strategy is very useful to beginners.
> Here's some code I wrote just the other day. It's specific
> to my system, I think the use of BSAVE for overlays is long gone, but
> it illustrates the point:
>
> : LOAD-SAMPLES ( startblock --)
> HERE ( save HERE to the stack)
> LATEST @ ( save LATEST to the stack)
> ROT ( get startblock to top of stack)
Come on, are these comments really necessary?
> BLOAD ( load the data)
> ( when BLOAD exits it has the next block number)
> ( on the stack, which is where the data for high)
> ( memory is, so just use it...)
> BLOAD ( load high memory data)
> DROP ( drop the block number left by BLOAD)
> LATEST ! ( restore LATEST)
> H ! ( restore HERE via variable H)
> ;
>
> Written horizontally then, it's:
>
> : LOAD-SAMPLES ( startblock --)
> HERE LATEST @ ROT BLOAD BLOAD DROP LATEST ! H ! ;
My question is, why was it necessary to save and restore LATEST and H?
It seems to me you've documented what is obvious, and not what the
reader who is trying to understand this code needs to know.
> The best one can do horizontally is use spaces to separate phrases.
> You've just got to hope that:
>
> a) The reader is experienced enough to be able to hang on and
> understand your code
> b) You are a good enough coder that your code gives the reader a
> fighting chance ;-)
>
> Commenting code written horizontally has always been an issue,
> particularly in a block based system, which is why the somewhat kludgy
> notion of shadow blocks exist.
A beginning Forth programmer needs more discussion and more help with
stack management, which is why a vertical style with comments on every
line is useful. But the comments are useless if they describe the
obvious and leave out the reasons why something is being done.
As one gains experience, the vertical style becomes less and less
relevant. In Western culture, we read horizontally, and can grasp
information more easily. It becomes a chore to read line after line
when there is very little new information per line. As you get more
experienced with Forth, you'll be able to judge when you reach this point.
When you're writing production code, you need to think of who is likely
to be reading this code. There are two possibilities:
1. It's you, several months later, and you need reminders.
2. It's someone other than you, maintaining your code, an unknown amount
of time later.
In both cases, it seems to me, the most important thing is to explain
*why* you're doing what you're doing (in the above example, why it was
necessary to save and restore these items), more than the minutiae. IMO
the possibility that it's #2 and this is a person who has never seen
Forth before is not worth considering. It's the responsibility of
whoever owns this code to ensure that whoever is maintaining it has at
least the basics of the language. But that person cannot know, and must
be told, what the rationale is for this code.
In one of my first programming jobs, I was given code that looked sort
of like this:
LDA,X \ Load X to A register
LDB,Y \ Load Y to B register
ADD \ Add X to Y
Come on, was this really worth typing? Would someone please explain
*what* X and Y are, and why you're adding them?
LDA,X \ Load addr of data buffer
LDB,Y \ Load offset to desired value
ADD \ Apply offset to get value address
Comments are essential, but they're valuable to the extent that they
actually tell the reader what's important!
Cheers,
Elizabeth
--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310-491-3356
5155 W. Rosecrans Ave. #1018 Fax: +1 310-978-9454
Hawthorne, CA 90250
CMOVE floats ?
> jeq cmvext
> mov @-2(stack),r1
> mov @-4(stack),r0
16-bit? I'd guess 16-bit from the 2 and 4. That assumes stack offsets are
byte based ...
> dec r2
> a r2,r1
> a r2,r0
> inc r2
> cmvflp movb *r0,*r1
> dec r0
> dec r1
> dec r2
> jne cmvflp
> cmvext ai stack,-6
> b @retB0
The syntax reminds me a bit of Herbert Kleebauer's assembler. He posts to
alt.lang.asm.
It could be a custom x86 assembler ... @ appears to be like $ current
address. The stack pointer is moved to r2, possibly dereferenced or fetched
in the process, the '*'. It takes two parameters (16-bit?) off of the stack
and moves them into r0, r1. These appear to be lengths. The stack pointer
in r2 is decremented. 'a' could be add. If so, it adds r0 and r1 to r2.
Then, it increments r2. It then moves a value from r1 to r0 or vice-versa,
since we don't know... It's possible that moved value is fetched or
dereferenced for both registers. Then, it decrements all three registers.
Loop until r2 is zero. I'm not sure why that'd work if the stack pointer is
non-zero to begin with ... Then, when the loop exits, it does a stack
cleanup. 'ai' could be signed add ... ? Then, it branches or returns. If
I assume it's x86, then it's a string copy of some sort, or perhaps a block
move.
> Anyone care to venture what it does? Probably not. The labels may
> give you a clue. Perhaps it's CMOVE? The labels sort of indicate that
> it might be, _cmovf and the like.
...
> Here's the code with comments:
> ;[ CMOVE> ( addr1 addr2 count -- )
>
> [snip]
>
Aw, I was right on the money, but I can't claim that now that you posted the
solution ...
BTW, why did you implement CMOVE in assembly? I guess you didn't see me ask
about why CMOVE was usually implemented in assembly in another recent thread
... I mean it could be implemented with LOOP yes?
Rod Pemberton
PDP-11 with slightly unusual mnemonics, I think.
Hi Rod,
Since you asked (don't want to hijack this interesting discussion)
it's TMS9900 - a 16 bit processor with quite a unique architecture.
First, God said "let there be light", then there was the wheel, then
there was the 9900.
@ = address
B = branch
A = add
* = 'contents of' (e.g. DEC *R1 = "decrement the value of the memory
location held in R1") - In Intel it would be DEC (R1)
Yep, it's 16 bit.
It's written in assembler because it's a 16 bit processor running on
an 8 bit bus, at 3mhz, with 32K of RAM. The people on CLF talk about
contraints! HA! THEY KNOW NOTHING! ;-)
Mark
He's basically asking for an assembly debugger, but for Forth. You know,
the ones that show the code being executed, the registers, stack, etc.
AISI, it would display the word being interpreted, the top items on each of
the stacks, any special "registers", that specific Forth's working
registers: IP, W, RP, SP, etc., whether the word is compiled or
low-level/primitive, perhaps in a corner of the screen or down the side. It
should work well for an interpreted forth, with many compiled words, and
very few primitives. Since I believe it's possible that one can reduce the
size of the primitive set to an extremely small quantity, a "teaching" Forth
could be implemented well, I'd think.
E.g., 9 to 12 primitives:
http://groups.google.com/group/comp.lang.forth/msg/5308eddbedcd558c
Also...
http://groups.google.com/group/comp.lang.forth/msg/537a79ec2270256a
Looking at it, I think he may have made some errors. ISTM, he uses STORE !
and COMMA , without any definition of them ... I also see no EMIT or KEY or
related I/O. He changes those 9 slightly for this one:
http://groups.google.com/group/comp.lang.forth/msg/d369aef98740bce0
Looking at that, I think he may have left out some code for it too. I can't
seem to locate CELL or CELLS ... It's interesting though that he somehow
managed to define PUSH and POP in Forth. Maybe he was executing on top of
another Forth. So, I think he had some bootstrap Forth or Forth-like system
in place for this work.
But, even so, one might get below 20, maybe below 16, primitives which would
allow for a very "watchable" Forth used for "teaching".
Rod Pemberton
TI99/4A? Chiclets! You know that thing is a collector's item, right? Not
to jinx you or nothing, but if it burns up or finally dies, you've lost your
"investment".
> It's written in assembler because it's a 16 bit processor running on
> an 8 bit bus, at 3mhz, with 32K of RAM. The people on CLF talk about
> contraints! HA! THEY KNOW NOTHING! ;-)
>
I'm sure some here programmed on 8-bit, or 16-bit, microprocessors with the
first generation of home PCs. I did, but not in Forth. A few here started
even earlier ...
Rod Pemberton
Yep, the TI-99/4A (which has a tms9900 in it).
> TI99/4A? Chiclets! You know that thing is a collector's item, right? Not
> to jinx you or nothing, but if it burns up or finally dies, you've lost your
> "investment".
I've got a garage full of them, plus SCSI cards, expansion boxes yadda
yadda ;-) Anyways, there's at least 4 really good TI-99/4A emulators.
My system was written using Classic99 on a laptop, as Classic99 has an
awesome debugger. Getting good quality 5.25" inch disks is the issue
these days, which is why we're moving to SD and other types of
storage.
It's so much more fun than a PC :-)
I've also got ZX81s, ZX Spectrums, Commodore 128s, Commodore Plus/4s
and a few other bits and bobs hanging around. That's when I'm not
playing my Les Pauls or Stratocasters! A man needs a hobby, you know.
Keeps him out of the pubs!
Mark
>I recently saw a video made by Samuel Falvo on text processing in Forth,
>at the end of which he says,
>
> "If you'll notice, nowhere in my code is there a stack comment.
> There's no need for it. The stack is kept so shallow that you can tell
> immediately by looking at one particular definition what's on the
> stack -- what is needed and what is the result of executing the code."
"If it was difficult to write, it should be difficult to read" (Anon).
I have heard the same from C programmers.
Elizabeth has already given her opinion. It is so close to mine that
I won't bother to express mine except that MPE is sometimes even
fussier than Forth Inc.
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
Ok, I'm sure I've spotted a pattern now:)
Python uses indentation to imply block structure. Occasionally this
can be annoying, for example, when pasting a line of code from a
file into the interactive console, and being told
"IndentationError: unexpected indent"
The rest of the time you are freed from having to us block markers
'begin ... end', and also from the differing styles of using them,
whether block format, aligned markers, or other. This removes
redundancy from the source code, making it slightly shorter, and
more consistently presented.
The indentation size, and other white space the programmer may
choose to good visual effect. Reading code, checking block
structures is perhaps a much easier, once a little familiarity is
gained.
Possibly it was a 'very very naughty boy' that imposed this
annoyance on you, or perhaps you are a parrot who is 'just resting'
- more sticky tape anyone?
Jan Coombs
Yeah, definitely. AFAICT the way people get things done quickly in
Forth is by solving only the simplest possible problem, hard-coding as
many assumptions as possible, and ignoring concerns like re-entrancy and
garbage collection and so on. So (outside of the commercial systems,
possibly) you don't tend to see much polished library code. Most of the
freely available stuff out there isn't worth building on.
> But I have heard some say that Forth is the language you can shape to
> your needs, and you don't have to shape yourself to the language.
Yes, but the farther your needs are from what Forth offers, the more
work it will be to shape the language. And at some point, there are
plenty of other languages which are much closer to the shape you need,
so why not use one of them?
> Right now I'm more interested in the practical aspects of learning to
> actually program in Forth rather than the philosophical issues
> surround The Forth Way (though I admit to being kind of sidetracked
> from my goal by this conversation).
The practical aspects are that you have to learn to be comfortable
juggling the stack in your head. It helps to try to think in phrases
which produce or consume one value or group of values. And you need to
memorize a basic vocabulary of the common words (and unfortunately there
are a lot of them).
When reading, I find that it's much easier to ignore the details at
first and try to follow the basic flow of the code, then go back and
fill in the details only where you really can't follow the code without
them.
And when writing, you need to learn to break problems down so that you
are only working with two or three values at once -- more than that is
generally too cumbersome to be readable.
Possibly the reason there isn't anything like Ketman's is that stack
visualization is such an essential skill that no one expects people to
really be trying to read code until they have that under their belt. I
know I feel like it might well be more of a crutch to help people avoid
learning to visualize by themselves. I'm not ruling out the possibility
that it might turn out to be a good tool for beginners, but I'm not
convinced enough to spend the time to write it.
And just out of curiosity, since you mentioned disliking the
inconsistencies of Forth, and missing garbage collection and other
modern conveniences; is there a reason you're trying Forth and not
Factor?
--Josh
Could you elaborate ion that exception? Certainly the user code is
not passed any information through the return stack when using DOES>,
nor does DOES> receive information on the return stack.
- 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 2010: http://www.euroforth.org/ef10/
> Coos Haak <chf...@hccnet.nl> writes:
>>The return stack is never (in standard words, the only exception being
>>DOES>)
>
> Could you elaborate ion that exception? Certainly the user code is
> not passed any information through the return stack when using DOES>,
> nor does DOES> receive information on the return stack.
>
> - anton
My mistake, internally I use the return stack to get the address of the
inline data.
This is an implementation issue:
Docol, docreate etc are implemented with jumps. My DOES> is internally
implemented with a call that places it return address on the return stack.
The part after DOES> uses R> to retrieve that address, but that's not
exposed to the user.
I agree, Standard Forth DOES> does not mention use of the return stack.
--
Coos
CHForth, 16 bit DOS applications
http://home.hccnet.nl/j.j.haak/forth.html
At a previous place of employment, I was reading some FORTRAN code
from a listing we had that was written at another company. A
comment over one routine said:
C This routine was hard for me to understand, and it's going to
C be hard for you to understand too, because I'm not going to
C tell you how it works.
--
+----------------------------------------+
| Charles and Francis Richmond |
| |
| plano dot net at aquaporin4 dot com |
+----------------------------------------+
I'd guess you'd collect old synth's too: Moog, Roland, etc. No? Well,
Roland has guitar synths too. The first versions are probably collectible
now.
RP
Indeed. I don't remember if I ever saw it mentioned here, but
there's a fantasy novels series, "Wizardry", by Rick Cook. There, the
protagonist is spelled onto a magic parallel reality by local wizards
that need his help. And he writes a magic interpreter/compiler, using
Forth techniques (it includes an explanation of the Forth interpreter,
EXECUTE, and so on). It is a fun read if one enjoys programming and
fantasy. The first two book are available for free from the publisher:
http://www.baen.com/library/rcook.htm
--
No, no, you can't e-mail me with the nono.
> > Assembly language isn't naturally interactive. Forth is.
>
> True. The value of something like Ketman's tutorial, which includes an
> assembly language *interpreter* is much higher for assembly language
> than for a language like Forth. But the instant visual feedback
> concerning the state of the virtual machine is equally valuable in both.
> When that sort of thing is tightly integrated with a tutorial, I think
> the combination is unbeatable.
I second that, it wasn't until Ketman's tutor that I really understood OR, AND, XOR, etc. Also his comments are well-timed and funny (Big Girls' Blouse). I'd like to implement something similar, since the Forth I use is written in assembler. Having it, I know I could have mastered it at least twice as fast.
Colin
There is something wrong with looking under the cover. And honestly
it relates to my aversion for stack comment of the sort
( d1,p -- d2).
Suppose I finally have managed to make a word:
"For DOUBLE (assuming it is a totient of something, otherwise throw
exception 1001) with respect to a factor PRIME split it into a totient
of a power of prime and a DOUBLE remainder. (taking advantage of the
fact that totient is a multiplicative function). "
The stack effect, implicit in the description, is like above.
Now once you have made this work, you never want to look back. 1)
If someone made it for you, you don't want to look under the hood.
If someone made it for you and didn't document it, are you really
looking under the hood to find out what it is supposed to do?
Fat chance! This is a real example, and it took me two hours to
write it. Reverse engineering takes about 10 times as long.
That is for some one at the same level of expertise and skill
as the writer.
Some of you may not even know what a totient or a multiplicative
function is and still be able to use it from the description.
This example also underpins Elizabeth Rather stand, disagreeing with
da Falvo. I dare anybody to make a Forth solution for problem 342 of
http://projecteuler.net without comment that is even remotely
understandable.
>
>How would visualising all of that on, say, the data-stack help you?
>You'd have some nice data set up on the stack, tab over to EXPECT,
>then maybe you type a line of text and press enter. Then a flurry of
>activity happens, and you are left a single item on the stack - the
>number of characters received. What does that tell you that you can't
>get from the simple comment:
>
>EXPECT ( address length -- receivedLength )
>Reads length characters of input from the current input device,
>storing them starting at address address, and stopping when a carriage
>return or an implementation specific maximum number of characters has
>been received. Upon completion, the number of characters actually
>received and stored is pushed to the stack. The terminating carriage
>return is not stored in the buffer, nor is it included in
>receivedLength.
>
>In fact, if you typed HELLO WORLD! at the cursor prompt when EXPECT
>ran, you'd probably have to look up the definition of EXPECT to
>understand the significance of the 12 that came back on the stack! ;-)
This is another fine example, why in understanding you must rely
on the documentation of the words, not on their source.
>
>Mark
>
1) Assuming you have secured your testset.
--
--
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
As a point of fact, I think you've got the timeline wrong. Sure,
Forth had its genesis in the 1960s, but FORTH, Inc wasn't founded
until 1973, and fig-FORTH, which introduced most Forth programmers,
was in 1979. So, Forth is about the same age as C.
> If that's not what your problem domain involves, Forth might not be
> that great a match for your purposes. These days if you want to
> write an EDSL for something other than a microcontroller, you are
> probably better off with Lisp or Haskell (depending on whether you
> want compiler-supplied static typing), even though both of those
> require much more powerful hardware than Forth does. Forth is of
> course still interesting as a pattern of thought, source of ideas,
> etc.
Forth is interesting for a number of reasons, but the most important
one is the proof that it's possible to make a powerful system
(i.e. one that permits substantial applications to be successfully
implemented) that is also very simple. That perhaps a great many of
the tools people use today, the compilers, debuggers, linkers,
makefiles, etc, etc, are as much a part of the problem set as part of
the solution set.
Moore: "The software provided with large computers supplies a
hierarchy of languages: the assembler defines the language for
describing the compiler and supervisor; the supervisor the language
for job control; the compiler the language for application programs;
the application program the language for its input. The user may not
know, or know of, all these languages: but they are there. They stand
between him and his computer, imposing their restrictions on what he
can do and what it will cost."
Andrew.
Interestingly, at my present work place, Java programmers are
forbidden from putting comment in their code. It is taken as
an indication that the code itself is not clear enough.
(I'm programming in assembler, and excempt from this rule.)
This is somewhat similar to Chuck Moore, who uses comment
sparingly and in shadow blocks, so as not to clutter up
his beautiful code.
I had this feeling once about my sudoku solver in Python:
that commenting it would serve no purpose, except to
make the code ugly.
>| Charles and Francis Richmond |
Groetjes Albert
Most of these comments are just noise. There's no point in saying in
a comment what an instruction does: it should say what a routine is
for. This is not an assembly language tutorial. Your reader already
knows what "movb *r0,*r1" does.
> And I think Forth words (perhaps not top-level words but certainly the
> lower down, nuts-and-bolts words) should be documented to the same
> level.
Heavens, no. :-(
> When I'm writing Forth code, I normally write it in a notebook first,
> with notes. Here's some code I wrote just the other day. It's specific
> to my system, I think the use of BSAVE for overlays is long gone, but
> it illustrates the point:
>
> : LOAD-SAMPLES ( startblock --)
> HERE ( save HERE to the stack)
> LATEST @ ( save LATEST to the stack)
> ROT ( get startblock to top of stack)
> BLOAD ( load the data)
> ( when BLOAD exits it has the next block number)
> ( on the stack, which is where the data for high)
> ( memory is, so just use it...)
> BLOAD ( load high memory data)
> DROP ( drop the block number left by BLOAD)
> LATEST ! ( restore LATEST)
> H ! ( restore HERE via variable H)
> ;
The trouble with this kind of bonkers over-commenting is that even
this simple routine takes a lot of reading. You are expecting your
reader to invest more time in studying this routine than it deserves.
It makes sense to comment when it's actually useful; the rest is
noise.
IMO this is better:
: LOAD-SAMPLES ( startblock --)
HERE LATEST @ 2>R
BLOAD
( BLOAD laves the next block number on the stack, which is where)
( the data for high) memory is, so just use it...)
BLOAD DROP ( load high memory data)
2R> LATEST ! H ! ;
> Written horizontally then, it's:
>
> : LOAD-SAMPLES ( startblock --)
> HERE LATEST @ ROT BLOAD BLOAD DROP LATEST ! H ! ;
But where is the comment that describes what LOAD-SAMPLES is for? I
presume there is one, but you haven't shown it.
Andrew.
Why, as a matter of fact, yes I do. I have a nice recording studio
here (nothing very grand) with a Yamaha AW16 track digital hard disk
recording system, Roland drum machine, a rack full of Roland JV1080's
( http://www.vintagesynth.com/roland/jv1080.php ) and an Atari ST
running CuBase to MIDI it all together.
Good fun, though I don't get much chance to use it these days! Funnily
enough I had a very (I think it was a Roland) guitar synth, but I let
it go via eBay as I wasn't using it. The chap that bought it was
delighted.
Mark
Although it's not a style I would feel comfortable with, I can see it
working if there was very close attention to naming conventions, and
the use of design patterns. And it might work if the code people are
writing is just adding on to an existing framework, and that framework
is in effect dictating what code will be written. But in order for
that to work, I would imagine that everyone who reads or writes code
has gone through some internal training on those conventions,
patterns, and frameworks. Anything less would likely lead to chaos.
> This is somewhat similar to Chuck Moore, who uses
> comment sparingly and in shadow blocks, so as not to
> clutter up his beautiful code.
Except beauty is often in the eye of the beholder. If the beauty of a
piece of code is based on some larger insight that only exists in the
programmer's head, what is beautiful for one person could be ugly for
another. Like most things in life, there needs to be balance. The
people who demand that every last line of code have a comment are
wrong. The people who think no code should be documented (without the
qualifications above), are wrong. In between, part of the skill of a
good software developer (versus one who merely follows rules) lies in
finding the edge between the two extremes.
ANS words are colored blue, so when you see one you don't recognize,
click on it and the appropriate documentation (draft ANS94) appears.
It would be nice to have mouseover stack pictures -- maybe I'll add
that. Almost all words have a hyperlink associated with them.
There is some Forth code at https://sites.google.com/site/forthtoychest/
that you might find interesting as a case study, since I have the
unusual habit of commenting my code. You could run it through
Forth2HTML (put Forth2HTML source in the same folder as the files you
want to convert), unzip the DPANS documentation
http://www.complang.tuwien.ac.at/forth/dpans.zip into a ./ANS/ folder,
and start browsing.
-Brad
That's a good point. When you see FOO referenced, you don't know its
stack effect unless you look it up. When that happens to me (and it
happens a lot), I quickly type LOCATE FOO.
-Brad
In my experience, Chuck *always* used stack comments (he invented them),
and often inserted brief other comments as appropriate. He invented
shadow blocks to hold lengthier text descriptions, usage info, etc.,
available with a single keystroke. As I was often in the position of
training customers to use his programs, I found this brilliant and quite
usable. It was a superb solution for documenting block-based code.
When FORTH, Inc. converted to file-based source, we adapted by putting a
section of comments before a group of related definitions, and have been
very happy with that arrangement.
And his code *was* beautiful.
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
The functionality is incomplete, but the STC version of Win32Forth
keeps the stack effects in the definition;
see dup
: dup ( 1 -- 2 ) \ ' nseopt compiles
\ len=6 type=7 flag=00
\ in src\kernel\gkernel.f at line 156
( $401267 ' dup ) mov $-4 [ebp], eax \ 8945FC
( $40126A ' dup+$3 ) lea ebp, $-4 [ebp] \ 8D6DFC
( $40126D ' dup+$6 ) ret near \ C3
( end ) ok
The intention was to extend this to other defined words apart from
primitive words. STE-CALC computes the stack effects;
0 ste-i ! ok
0 ste-o ! ok
1 2 ste-calc ok ( a -- b c )
3 1 ste-calc ok ( a b c -- d )
1 2 ste-calc ok ( a -- b c )
ste-i @ . 2 ok ( overall in )
ste-o @ . 2 ok ( overall out )
But it never got completed, since there are a number of problems. Not
the least of which are words with unknown stack effects, like ?DUP and
anything involving a loop.
http://www.colorforth.com/ide.html
No stack comments. Odd notation (/8 for shift right eight), possibly
due to limited character set. Magic constants. Nddlsy abbrvtd wrds
dnt hlp, but since vowels cost money (at least on "Wheel of Fortune"),
think of the savings!
Yes, it's ColorForth. And yes, the point of the code was probably to
cause awe in easily impressed people about how little code is needed
when writing direct to specific hardware for a specific disk
controller wired to a specific address, and ignoring the performance
gains of DMA transfers.
There may have been beauty then, but now, if there is beauty, its
found in the system, not the source. At least not in public examples.
Unfortunately, I agree with you. I find ColorForth to be pretty
incomprehensible. It's optimized for the computer, rather than for
humans, which I find to be a serious mistake. They're going to have
trouble getting general acceptance so long as users are required to use
ColorForth.
Greg Bailey has just recently developed a version of polyFORTH for the
GA parts. I don't know if it's been publicly released yet.