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>