[comp.lang.forth] NUMBER and block files and ANS Forth

wmb@MITCH.ENG.SUN.COM (06/30/90)

FS> (It was more amusing, though, when I thought you  objected to it being
FS> one giant file at the same time Robert objected to  it NOT being one
FS> giant file.)

This is the kind of problem that the ANS Forth committee has to deal with
every issue.

In this particular case, ANS Forth gives you both choices, in a particularly
nifty way:

	BLK	SOURCE-FILE	Input source
	------------------------------------
      nonzero       0		Block from "global block space", i.e.
				entire disk farm is one giant array of blocks

      nonzero	 nonzero	Block from file whose descriptor is
      				contained in SOURCE-FILE

         0	    0		Keyboard

	 0	 nonzero	Text file whose descriptor is contained
	 			in SOURCE-FILE


FS> ... discussion about how to implement NUMBER? so a program can parse
FS> without risking an ABORT ...

If you have CATCH and THROW , the obvious implementation of ABORT is
"-1 THROW".  This turns out to be an excellently useful thing, because
then a program has the option of handling any ABORT condition that arises.

In this case, NUMBER? is trivially defined as:

	: NUMBER?  ( a -- d flag )
	   ['] NUMBER  CATCH  IF   ( x )
	      DROP 0 0  FALSE      ( 0 0 false )
	   ELSE			   ( d )
	      TRUE		   ( d true )
	   THEN			   ( d flag )
	;

An even better approach is to let the application take care of
CATCH'ing the call to NUMBER, because that gives the application
the flexibility of choosing the level at which to handle the error
(which might be several levels up from the actual call to NUMBER ).
This can eliminate several levels of "passing flags back up".

CATCH and THROW: Try it, you'll like it.

Use it in your kernel, and your kernel may get smaller (mine did).

One other observation:  Implementing ABORT with CATCH and THROW
eliminates the one "unavoidable" forward reference in the Forth kernel
(the ABORT - QUIT - INTERPRET - NUMBER - ABORT cycle).  A kernel with
CATCH and THROW can be compiled entirely incrementally.

Mitch

dwp@willett.UUCP (Doug Philips) (07/03/90)

wmb@MITCH.ENG.SUN.COM, in <9007020308.AA02478@ucbvax.Berkeley.EDU>, writes:

> If you have CATCH and THROW , the obvious implementation of ABORT is
> "-1 THROW".  This turns out to be an excellently useful thing, because
> then a program has the option of handling any ABORT condition that arises.
> 
> An even better approach is to let the application take care of
> CATCH'ing the call to NUMBER, because that gives the application
> the flexibility of choosing the level at which to handle the error
> (which might be several levels up from the actual call to NUMBER ).
> This can eliminate several levels of "passing flags back up".

The problem with letting things THROW several levels up, is in
determining what error condition you are CATCHing.  Without named
CATCH/THROW tags how could you know?  A generic abort isn't really all
that useful unless you are careful to catch close enough around anything
you care about so that nothing else accidently sets off that CATCHer.  I
suspect that that just can't work because you never really know what the
CATCH protected word might end up invoking.  I suspect that you also
need to put a generic "some bad thing happened somewhere" CATCHer in the
top level word of your application, but even then recovery is somewhat
problematic when you don't know what you're recovering from.

> One other observation:  Implementing ABORT with CATCH and THROW
> eliminates the one "unavoidable" forward reference in the Forth kernel
> (the ABORT - QUIT - INTERPRET - NUMBER - ABORT cycle).  A kernel with
> CATCH and THROW can be compiled entirely incrementally.

This says to me that there is something fundamentally "right" about
CATCH/THROW.  That there is a new "factoring" in the kernel which is
technically superiour to the old "factoring".  I haven't personally
written enough Forth code of any kind to assess the practicalities of
this "improvement."  My experience with other languages says it works
well, but that makes me less inclined to trust that experience.

I'm curious to know (if you follow-up to this question perhaps a
change of Subject line is in order) how various implementers have
"evolved" their kernels in order to make them simplier and easier to
meta-compile.  This is a very general question.  I would be curious to
look at the overall structures of various Forth kernels to see if
"independant" evolution arrived at some small number of techniques.
I'm not talking "(in)direct-threaded vs. subroutine" but the way in
which the particular Forth's "core" word set is organized.  (Not that
I particularly have the copious spare time, nor the analytically skills
to extract that kind of information from FORTH code...)

-Doug


---
Preferred: willett!dwp@hobbes.cert.sei.cmu.edu OR ...!sei!willett!dwp
Daily: ...!{uunet,nfsun}!willett!dwp   [in a pinch: dwp@vega.fac.cs.cmu.edu]

peter@ficc.ferranti.com (Peter da Silva) (07/03/90)

In article <9007020308.AA02478@ucbvax.Berkeley.EDU> wmb%MITCH.ENG.SUN.COM@SCFVM.GSFC.NASA.GOV writes:
> CATCH and THROW: Try it, you'll like it.

I still think setjmp semantics are superior to catch/throw. I implemented
catch and throw in Forth nearly 10 years ago, and switched to setjmp
style semantics shortly thereafter. You can easily implement the semantics
of catch and throw using setjmp and a common jmp_buf, but the reverse is
not true.

And once you have setjmp, implementing threads becomes a SMOP.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.
<peter@ficc.ferranti.com>