Not long ago I placed the .zip ed form of the FORTH primer disk I developed
for ACM SIGForth etc. on the ftp site pub/forth/ at netcom.duke.edu
There was an interval when the site was temporarily closed down, but it
should be ok again by now. If not let me know and I will remonstrate.
I can also place it on the site ftp.virginia.edu (but they only allow
a 2 week residence time so I would have to keep posting it). It contains
f-pc 3.56 and lots of good stuff.
The chief reason FORTH does not bother with integrated debuggers,
development environments, etc. is that it generally has no need for such.
I usually install SideKick as a TSR pop up editor and then run FORTH.
Most PC FORTHs will not interact badly with SideKick. VEDIT will also
work as a FORTH development editor. And of course, F-PC has an integrated
editor (as do many commercial FORTHs such as HS/FORTH). That's really all
you need. You develop FORTH by defining one word at a time. It is
fairly easy (on the PC, at least) to log all input keystrokes to a
permanent file (I usually write to a floppy) so you know what you have
done, especially if you crash the system. I describe how to do this
in my book, "Scientific FORTH: a modern language for scientific computing".
So when you define a word, you test it. Usually this involves only placing
some numbers on the stack and seeing whether the new word does what
it is supposed to. At worst, a TRACE (most FORTHs either provide something
like a single-stepper or make it easy to define one) gives you a dynamic
view of the stacks during execution for complex definitions, thereby
locating incorrect stack handling (the source of 90% of errors) very
quickly. But mostly, if you adhere to the discipline of keeping definitions
brief (typically 7-10 words long) you will not even need tracing or single-
stepping. The errors will be obvious.
Remember, FORTH is the most highly structured programming language in
current use. There are absolutely no goto's and definitions have single
entry and exit points. This makes it easy to write correct code if one
adheres to some simple disciplines (documenting, word length, stack
diagrams, keeping stacks small, etc.). One almost never requires the
sophisticated arsenal of on-line help, embedded debuggers, hardware
debuggers, assertions, object viewers, logic compilers, etc. that one
has come to expect with languages like C++.
Ciao and good luck--welcome to the fold.
--
Julian V. Noble
j...@virginia.edu
I'm new to the fold and read your message with great interest.
Decided to have a look for myself so tried ftp'ing to oakland using
'anonymous' for name. Told me to P*** off!
Regards,
Confused ( better known as Tony R-A )
JVN> Remember, FORTH is the most highly structured programming language in
JVN> current use. There are absolutely no goto's and definitions have
JVN> single entry and exit points.
Well, I don't know about other forth's, but there is a word called return in
JForth. Why should it be a bad thing with something like return? Of course one
could(/should?) *always* code in a different way and avoid multiexits.
JVN> This makes it easy to write correct code
JVN> if one adheres to some simple disciplines (documenting, word length,
JVN> stack diagrams, keeping stacks small, etc.). One almost never requires
JVN> the sophisticated arsenal of on-line help, embedded debuggers, hardware
JVN> debuggers, assertions, object viewers, logic compilers, etc. that one
JVN> has come to expect with languages like C++.
I would like some kind of sourcecode-browser though, for use with code I didn't
write.
JVN> Julian V. Noble
JVN> j...@virginia.edu
o/~ Bye bye...
Mvh: Tommy <# Amiga JForth + Power = if ." Yeah!" else abort" Error!" then
IRC: D-Bug M 2:203/424.5@FidoNet InterNet: Tommy_H...@p5.trh.bbs.bad.se
... H.ller man fingrarna i styr s. h.nder ju ingenting!
condition1 IF EXIT ELSE stuff THEN
condition2 IF EXIT ELSE stuff THEN
etc.
But this is simply a way to accomplish the same thing as nested IF
statements in a more readable form, so I don't think of it
as truly producing multiple exits, especially if each EXIT leaves
the same number of things on the stack.
> Of course one
> could(/should?) *always* code in a different way and avoid multiexits.
I've never quite understood why as designers of software, we have to be
constrained by the popular thinking of others, particularly when it boils
down to preferences.
The GOTO statement can be a damn useful function/word at times, and
although I can't remember the last time I used it, I certainly wouldn't
rule it out because it isn't considered fashionable ( For those of you
who are about to say that the reason it ain't used is because it is bad
design... thats wot I mean by fashionable!! ).
In fact, real programmers, and before you all bristle at this : Yes , my
preferred programming language is and always will be FORTH, and by real I
mean ASSEMBLER programmers, cannot avoid the use of the GOTO statement..
only it's called a JUMP. That's the funny thing. People spend ages
avoiding GOTO, then their compiler spends ages working out how to convert
their carefully designed code into JUMPs!! Ironic! :-)
PS: The best thing about FORTH is designing ASSEMBLER routines you can
test interactively.
Go FORTH and *
Tony R-A
Although it is true that the compiler converts one's code to JUMPs of
various sorts, it is also true that the disassembled code is usually
unreadable. The point of using control structures is to make the code
clear. Everyone knows that 0BRANCH and BRANCH--components of IF...THEN
and BEGIN...UNTIL structures--produce conditional jumps. But as long
as we do not need to see these jumps explicitly, the control flow remains
clear.
While I agree with you that the ASSEMBLER is ***ONE*** of the best things in
FORTH--so much that I am just now writing an article for Computers in
Physics that touts FORTH on the basis that it lets you design and test
assembler routines rapidly and safely--I believe that the ***best***
thing about FORTH is its accomodation of fine-grained decomposition and
factoring. Programming is easier when you can un-nest loops. For example,
if one wishes to transform a column vector by multiplying it with a matrix
i.e. w = M v, one might say
w{ }len 0 DO
M{{ I \ info on I'th row
v{ \ info on col. vector v
row.col ( :: -- result)
w{ I } FS> \ result -> I'th elt of w
LOOP
where row.col supplies the inner loop, and the names w{, v{ and M{{
supply, respectively, the needed information as to data type, address,
etc. The operators }len and } get the size of the vector (to put in
the upper index of the DO ) and compute the offset, respectively.
That is, w{ I } leaves the address and type of the I'th element of w,
and the generic store FS> pops the generic result from the top of the
floating point stack to that element.
The point is the control flow is much clearer when done this way, than in
a longer program with explicitly nested loops. FORTH makes it easy. FORTRAN
makes it near-impossible.
Taking your answer as read ( which saves me copying the whole lot down
here ) I agree with the point you make about readability... mypoint was
that we shouldn't be constrained from using any method as long as it
works efficiently, if a GOTO is appropriate then use the damn thing! ( if
necessary do what a pal of mine does and add a apology in comment!! :-) )
As to your second point, I won't argue with you, since it's a matter of
opinion. I started my s/w design in BASIC,then C followed by FORTH then
Assembler and in truth I like the latter the most. FORTH does however
beat assembler hands down but does allow me to indulge!
Regards
Tony
--
Michael Coughlin mi...@gnu.ai.mit.edu Cambridge, MA USA
At least the code in Forth can be made to be self-commenting:
: send_data() \ char -- t/f
open_port()
send_char_to_port()
confirm_successful_TX()
;
Where do I need the comment in that word definition????
Luckily, writing most code without a single GOTO is SIMPLE!
All that's needed is to think of code as structured nested
components instead of thinking of it as a flowchart. Consider
a loop or a conditional construct as an approved GOTO. Other
uses of it rarely have a good reason (although sometimes they do).
Leaving them out has pragmatic advantages as well, since compilers
can do their job more effectively (except in FORTH, where
programmers demand that compile not do anything clever, lest
they be unable to use certain hacks).
> >I mean ASSEMBLER programmers, cannot avoid the use of the GOTO statement..
> >only it's called a JUMP. That's the funny thing. People spend ages
> >avoiding GOTO, then their compiler spends ages working out how to convert
> >their carefully designed code into JUMPs!! Ironic! :-)
It's not ironic, and it's a completely stupid argument, IMHO. Sorry
to be so blunt, but really, it's just a dumb argument. It's the sort
of argument that implies you haven't programmed for very long even if
you have. A structured component naturally breaks down into GOTOs,
but that doesn't mean the programmer should abandon them and use GOTOs
instead. Assembler is a low level language, not meant to be easily
read, maintained, debugged, etc. A high level language is different,
and what's good for one is not appropriate for the other. Assembler
is meant for the CPU to understand and execute; high level languages
are meant for humans and compilers.
--
Darin Johnson
djoh...@ucsd.edu
- Grad school - just say no.
What are the side effects? Sure, I know what this routine
is probably going to do, but to be able to use it I need to
know a lot more. What port will it use? What happens if
open_port() fails, is there a throw done? Do I need to
close the port when it's all over? What if I send data to
an already open port?
It's a pain to have to read all of the words that this one
uses just to figure out what's going on. I think that it's
partly a result of a lot FORTH programmers, who are sole
programmers on a project, so no need to worry about commenting
for other people. (ie, what if the person who wrote send_data
wasn't the same person that wrote open_port, and isn't the
same person that will be calling send_data...)
--
Darin Johnson
djoh...@ucsd.edu
Ensign, activate the Wesley Crusher!
> It's not ironic, and it's a completely stupid argument, IMHO. Sorry
> to be so blunt, but really, it's just a dumb argument. It's the sort
> of argument that implies you haven't programmed for very long even if
> you have. A structured component naturally breaks down into GOTOs,
> but that doesn't mean the programmer should abandon them and use GOTOs
> instead. Assembler is a low level language, not meant to be easily
> read, maintained, debugged, etc. A high level language is different,
> and what's good for one is not appropriate for the other. Assembler
> is meant for the CPU to understand and execute; high level languages
> are meant for humans and compilers.
Whoa, take it easy!!
Statement of fact:
1. It is ironic! Think about it... there are people that will spend ages
designing code that specifically avoids the GOTO statement only to have
it undone by the compiler. I wasn't arguing that a program should be
written solely using GOTOs. Read the text: There should not be a
constraint on the way we design code was the argument I was putting
forward, and was using the GOTO as an example. Interestingly, you brought
up the FORTH programmer's bug-bear: the return stack! Why not allow us to
muck about with it. The whole philosophy of FORTH is anything goes, there
should be no restraints. So that for example, I can design a recursive
word in FORTH that will *never* crash the stack, which other language
allows that? ( bar assembler)
2. Don't jump to conclusions about some-one's programming ability if you
haven't read their code. IMHO, you want to be careful of how you insult
people around April 1st.
3. Assembler was designed for humans actually, Machine code instructions
were made for the CPU. Some assembler implementations these days look
just as high level as FORTH or C , if you can these 2 high level!
>Luckily, writing most code without a single GOTO is SIMPLE!
>All that's needed is to think of code as structured nested
>components instead of thinking of it as a flowchart. Consider
>> >I mean ASSEMBLER programmers, cannot avoid the use of the GOTO statement..
>> >only it's called a JUMP. That's the funny thing. People spend ages
>> >avoiding GOTO, then their compiler spends ages working out how to convert
>> >their carefully designed code into JUMPs!! Ironic! :-)
>It's not ironic, and it's a completely stupid argument, IMHO. Sorry
>to be so blunt, but really, it's just a dumb argument. It's the sort
Furthermore; not all CPUs Have to have GOTOs
I know of at tow CPUs that emply Forth and pascal as the machine
instructions themselves. Its called a zero parameter base language.
Just my $0.02 worth }:->
--
--------- #include <side_splitting_totally_tasteless.joke> ---------------
cwy...@nyx.cs.du.edu | Famous Last Words - I was only Trying to help...
Good advice is ignored. Ok advice is used. Bad advice is flammed forever.
Who? ME? I Deny Everything!!! It wasn't my code that ate the payroll file!
There are so many dubious statements in this posting that it's hard
to itemize them all. As I remember, you have admitted in the past
that your practical experience in these areas is minimal. Please don't
judge, or lead others to judge, Forth coding style by the code you see
published in Forth Dimensions, Ting's books, or old issues of DDJ.
In my own experience, people that write Forth code for a living (as
opposed to those who feel some religious mission to create yet another
public domain Forth) write very readable code and make generous use
of comments. They have to, in order to survive.
--
Tom Almy
tom....@tek.com
Standard Disclaimers Apply
>In my own experience, people that write Forth code for a living (as
>opposed to those who feel some religious mission to create yet another
>public domain Forth) write very readable code and make generous use
>of comments.
What about people who write Forth code for a living and
also feel some religious mission to create yet another PD Forth? :-)
But Ray's right about comments: Good Forth programmers comment.
My own Forth commenting style is very similar to my assembly commenting
style ... I format vertically, with indents for control structures, and
there's a comment for nearly every single line. I also wrote programs
that extract my comments into textual documentation (long before Knuth
wrote CWeb!!).
=jax=
--
#j...@cygnus.com # I'm not allowed by federal election
#j...@well.sf.ca.us # law to tell you that I'm running for
#72203...@compuserve.com # Congress in Colorado's 6th District.
#SYSOP RCFB (303) 278-0364 # Email jwo...@well.sf.ca.us
I'd like to see such an example.
Well, I guess by the same token, the following statement is ironic:
Many programmers spend a lot of time and effort putting comments
in their code, only to have them removed by the compiler.
> 2. Don't jump to conclusions about some-one's programming ability if you
> haven't read their code.
I didn't explicitly say anything about your ability, but I was
strongly reminded just-past-the-novice-stage C programmers who
insist on programming at as low a level as possible (usually
hand optimizing their code based on a PDP 11 machine model).
> IMHO, you want to be careful of how you insult
> people around April 1st.
I've always thought that was the best time to do so (then the
target never knows if the insult was serious or not :-)
> 3. Assembler was designed for humans actually, Machine code instructions
> were made for the CPU.
Branch instructions were designed for the CPU (the assembler part
for these is just a way to avoid typing the machine representation).
Macros and the like are the things designed for humans to read.
I'm sure you get the point though - jumps are more appropriate for
CPUs, if it's in their instruction set, and less appropriate for
humans, where it leads to unmaintainable code. (I'm NOT saying
they should never be used)
I wonder if this is partly a Forth-ism. Most Forths are very
low level, exposing much of the underlying machine model, and
implying a concrete instead of language model (that ANS is
trying to move away from). As such, it's natural for people
from this model to think jumps are great.
--
Darin Johnson
djoh...@ucsd.edu -- Toy cows in Africa
I couldn't agree with you more. I commented my polyFORTH code at FORTH,
Inc. more than I ever comment my C code these days.
So what happened, did the hardware guys assume you'd done an April Fool
on them?
Tony R-A
tst...@cix.compulink.co.uk
> I'd like to see such an example.
You weren't supposed to do that! It's been ages since I did this so bear
with me.
This came about from one of those computer magazine *let's see how many
clever dicks there are out there* programming competitions. It was one of
those mathematical problems: start with a seed if even then divide by 2
else divide by 3 add 1 recurse unless 0 or 1 I think. Basically, most
seeds meant that recursion would go on for some time, may even cause a
machine crash to occur because theprogram used up the stack.
I can't remember the exact algorithm, so I've substituted a simple one in
its place to demonstrate the principal
hex
variable 1st_iter
: test_word() \ --
1st_iter @
if
-1 1st_iter ! \ 1st pass of recursion set flag
on
else
r> drop \ subseq passes, drop nested
return
then
key dup emit 0d <> \ wait for key input,chek for CR
\ and emit all at the same time
if
recurse \ recurse if not CR
then
;
The point is to ensure that the word doesn't keep nesting in the
recursive trap so that exit will take place only once. OK?
Yes, there were no specific jump instructions. While RET may jump, it is a
*structured* jump and (if done at the end of procedures) is a valid part
of structured programming. The instruction set could handle all HLL control
structures, but could not (by design) implement a HLL "goto".
>So what happened, did the hardware guys assume you'd done an April Fool
>on them?
Actually, *I* was a hardware guy at the time (after all, I was designing
processors). They got a good laugh. I think people would have been scared
to have a processor that didn't allow compiling "gotos".
> > I'd like to see such an example.
>
> You weren't supposed to do that!
Ah well...
> hex
> variable 1st_iter
>
> : test_word() \ --
> 1st_iter @
> if
> -1 1st_iter ! \ 1st pass of recursion set flag on
> else
> r> drop \ subseq passes, drop nested
> return
> then
>
> key dup emit 0d <> \ wait for key input,chek for CR
> \ and emit all at the same time
> if
> recurse \ recurse if not CR
> then
> ;
First, yanking stuff from the return stack is a big no-no!
The biggest reason for this is that you can never be sure what's
on there - not all Forths are implemented the same way, and many
don't even use threaded code! Sure, this will work for certain
versions - but it's equivalent to directly mucking with stuff
in other languages (peek/poke in basic, #asm in C, etc).
Second, many languages can do this automatically using
tail-recursion optimization (ie, convert into a loop).
So there's really nothing here that makes Forth superior
to other languages in this regard.
(finally you forgot to set 1st_iter back to its initial value, but...)
I think this philosophy in Forth of subtle encouragement to muck
with that best left unmucked is changing in the ANS standard,
since it impedes development of the language.
First, yanking stuff from the return stack is a big no-no!
The biggest reason for this is that you can never be sure what's
on there - not all Forths are implemented the same way, and many
don't even use threaded code! Sure, this will work for certain
versions - but it's equivalent to directly mucking with stuff
in other languages (peek/poke in basic, #asm in C, etc).
Seriously, isn't that the point of FORTH? I appreciate the need for well
structured easily readable code, hell, I always *try* to comment my code
as I go along. The point is that I use FORTH *because* I can do the kind
of things you frown on. I develop embedded code for a company that needs
code developed quickly. If they want a change made, it usually has to be
in a 24-hour turnaround. Hell, I've developed code on site at times, and
I'm not talking bug-fixes.
So, I *know* what my version of FORTH does and can do. I suspect most
FORTH developers are the same. Granted there sometimes appears to be a
kame-kaze attitude amongst FORTHians, particularly firmaware engs, and
ANS does seem to be driving us out. I won't comment on whether that's a
good thing or not. I suspect you know how I feel about it! :-)
Regards,
Tony R-A
tst...@cix.compulink.co.uk
I love these saying people put on the end of their messages. Is there a
protocol one has to follow or what?
>> The whole philosophy of FORTH is anything goes, there
>> should be no restraints. So that for example, I can design a recursive
>> word in FORTH that will *never* crash the stack, which other language
>> allows that? ( bar assembler)
>hex
>variable 1st_iter
>: test_word() \ --
> 1st_iter @
> if
> -1 1st_iter ! \ 1st pass of recursion set flag
>on
> else
> r> drop \ subseq passes, drop nested
^^^^^^^
> [...]
On my system, this would definitely crash not only my stack but also my
whole computer :-) [on exit of test_word]
Say, do we need a common word to remove the latest return address from
the stack? I propose:
----------------------------------------------------------------------
ABANDON
Interpretation: Interpretation semantics for this word are undefined.
Execution: ( -- ) ( R: nest-sys -- )
Discard the topmost nesting information from the return stack.
An ambiguous condition exists if the nesting information is
unavailable.
See: 3.2.3.3 Return stack , 6.1.2380 UNLOOP
----------------------------------------------------------------------
to do this.
It can be implemented as equivalent to "r> drop" for most ITC systems or
on systems like F-PC equivalent to "2r> 2drop".
Other systems may implement it differently.
Concerning your example: Why not use a loop in the first place?
Ulrich
--
Ulrich Hoffmann email: u...@informatik.uni-kiel.de
Institut fuer Informatik, Universitaet Kiel Tel: +49 431 560426
Preusserstr 1-9, D-24105 Kiel, Germany Fax: +49 431 566143
> Concerning your example: Why not use a loop in the first place?
Appreciate that would be the obvious way , I was demonstrating ( or at
least was trying to demonstrate :-) ) how to protect the return stack in
recursion using FORTH. The original problem that a magazine set was to
specificaly use recursion to solve the problem. I couldn't remember the
original and used that algorithm in its place. I shall try to find the
original sometime and post it here.
Tony R-A
tst...@cix.compulink.co.uk
Ps: Thanx for >field: 8殃