Threaded Interpretive Languages 
Author Message
 Threaded Interpretive Languages


Quote:
> The prototypical TIL is FORTH. There is a newsgroup comp.lang.forth on
> which you can read the often convoluted expressions of dedicated FORTH
> programmers. A nice article on the history of FORTH appeared in BYTE
> Magazine September 1980 (written by its creator, Dr. Charles Moore).

It depends on what you mean by "prototypical". Clearly, it is the best known.
The 1980 article is not exactly precise about dates of the various
developments. The POP-1 language (Package for Online Programing) that we
developed in Edinburgh University in 1966-68 used TIL technology combined with
reverse polish notation. Syntax was quite like early Forth, using FUNCTION and
END delineation of function definitions. This is described in the Machine
Intelligence Series:

Popplestone R.J.[1968] "POP-1: An Online Language" in Machine Intelligence 2,
Eds. Dale,E. and  Michie D, Oliver and Boyd, Edinburgh Scotland.

Threaded -compiled- code arrived with POP-2 in 1968, which also used a
compiler providing an Algol-like syntax, developed from Rod Burstall's REVPOL
function written in POP-1, which -produced- the reverse-polish form as output.

Burstall, R.M. and Popplestone, R.J., [1968] The POP-2 Reference Manual,
Machine Intelligence 2, pp. 205-46, eds Dale,E. and Michie,D. Oliver and Boyd,
Edinburgh, Scotland.

Quote:
> In many ways FORTH is like Lisp (or perhaps Lisp is like FORTH? :-), ex-
> cept it uses postfix ("reverse Polish") rather than prefix notation.

Well... certainly LISP  came first.  An important dimension  of difference  is
garbage collection. If you garbage collect in a non-statically-typed  language
you are rather forced into tagging (I don't regard conservative collection  as
a serious  option). Forth,  if I  understand  it rightly,  is not  tagged  (an
advantage for systems applications) and not garbage collected. POP-1 and POP-2
were, and POP-11 is. This was  seen as essential for the symbolic  programming
needed  for  AI.  However  it  made  for  implementations  which  were  a  bit
complicated for early micros.  Bill Clocksin did a  version for the DEC-11  in
1968, called "Poppy", I seem to recall.

Quote:
> In addition, the programmer has direct access to the main stack (parameter
> stack) of the cpu. Stack access + RPN greatly reduces the overhead of
> subroutine calls, hence encourage the fine-grained decomposition of
> programs into small functional units that do only one thing. For this
> reason FORTH programs tend to be vastly shorter and to use much less
> memory than equivalent programs in other languages. Typical automated
> measures of "program complexity" applied to FORTH code yield very low
> indices even for programs I would regard as complex.

Now it is clearly -false- that "Stack access + RPN greatly reduces the
overhead of  subroutine calls". RPN is quite irrelevant - any syntax can be
mapped into reverse polish form, and in elementary compilers often is.
Requiring stack access constrains a language implementation in a way that maps
quite well onto many complex instruction sets, but poorly onto RISC. What -is-
true is that complex (but still inadequate) rules for handling free variables,
as in Pascal, do make it hard to have low-overhead function calls. But the C
language is less constrained than more direct descendents of Algol 60. Any
technique used for implementing function call in FORTH is equally applicable
to C, but not conversely. In fact, the -open stack- if it contains only
arguments imposes an overhead in that a separate pointer to it is required,
using up a precious register.

Where there is -gain- in writing these languages over others is typically that
it is much less work to do in I/O, generating test data etc.. The availability
of a compilation mechanism at run-time also saves a lot of effort.

Moreover with a language that supports  in-lining [like C++ (not my  favourite
by the way) or Haskell say] a big win is possible, since a small function  may
inline in less space  than its call  takes, and is of  course faster. This  is
directly opposed  to threaded-code,  where by  definition the  small  function
-must- be called, since it may be redefined. Typically threaded code is useful
for -debugging- but it is best converted into an unthreaded form for use  in a
module like a mailer where it will be normally used unchanged.

There are  -advantages- to an open stack, but they are not those claimed.

(a) By providing a simple method of passing arguments it is easier to define
certain higher-order functions. Thus  -newarray- in POP-2/POP-11 takes a list
of bounds and a function of n-arguments, and returns a -memoised- version of
the function. It is easier to implement various kinds of memoization in a
general way with an open stack.

(b) The open stack provides what is in effect cheap storage, and supports
cheap multiple-value return in a way that allows tuples so returned to be
associatively combined. For example, the POP-11:

define flat(T);
  define flat1(T);
    if is_node(T) then flat1(left(T)); flat1(right(T));
    else T
    endif
  enddefine;
  [% flat1(T) %]
enddefine;

works by -stacking- the leaves of the tree in the inner -flat1- function.
Rod Burstall's [% .... %] construction converts the stacked values to
a list on the heap. This function is O(n), whereas an implementation
using -append- would be O(n^2). And any O(n) implementation in a
non-open-stack language is conceptually complicated by having to pass
an argument in which the result can be accumulated.

Quote:
> FORTH is incrementally compiled. The compilation mechanism is part of the
> language and its components accessible to the programmer. This latter
> feature distinguishes FORTH from all other languages I know. (Maybe Lisp
> does it too? Don't know enough about it to say.) As a result, the user can
> try something out as soon as it is defined. For example (a trivial one, to
> be sure!) suppose we define a new FORTH subroutine (everything in FORTH is
> a subroutine, called a "word", just as everything in C is a function):
>         : *+   * +  ;  ( a b c -- b*c+a)

POP-11 is rather more verbose. The direct equivalent:

    define *+ (/*a,b,c*/); * + /* b*c + a */ enddefine;

But you can write:

    define *+ (a,b,c); b*c+a enddefine;

Quote:
> The colon ***is*** the compiler. It is a FORTH word that makes a new
> dictionary entry with the name *+ .

There are some disadvantages to this kind of approach. In fact Rod Burstall
urged that we should use an abstract syntax for POP-2, rather than having
the whole compiler driven by "immediate action" tokens. The primary
disadvantage is that any manipulation of a program is tricky. For example,
you might want to run some code through an algebraic simplifier, perhaps
with some parameters bound. This is in principle easy in LISP (though in
practice made difficult by the baroque way the language has developed).
Typically it means that LISP macros are more sophisticated than POP-11 ones.

Significant program manipulation is hard in both POP-11 and FORTH - the
applicative form of a reverse polish is only determined -when- you know the
arity of the symbols. With threaded code, this is potentially rebindable at
any time. Thus the *+ example above might as well be logsin, with a different
applicative structure.

FORTH:

        3 4 5 *+ .  23 ok

Quote:
> (The dot or period is a word that says "emit the number on the top of the
> stack, consuming it in the process". FORTH words usually consume their
> arguments.) We see the word *+ did precisely what it was supposed to,
> hence it is debugged and can be marked "tested" in the source code.

POP-11:

    3,4,5, . *+ =>

** 23

Here the "." says "do it" as opposed to pushing a pointer to the code
on the stack for supplying the function as an argument to another function.
The "=>" means "print the entire contents of the stack".

More conventionally

    *+(3,4,5) =>

** 23

Quote:
> So one of the major advantages of a TIL like FORTH is the ease of
> developing and debugging code. None of the cumbersome accessories of the
> more mainstream languages -- programming editors, interactive de{*filter*}s,
> MAKE -- are needed in FORTH. This means FORTH can be written and debugged
> quickly on small machines.

Now here we come to the main issue. POP-1 -was- a small language. POP-2 larger
and POP-11 has grown to be big by some people's standards, though smaller
than Common Lisp systems. Now various languages have made much bigger market
penetration because of being -at- the right time -in- the right place and
-with- the right facilities. Some facilities at some times represent overkill,
but they may be seen as essential later. The primary facility that comes to
mind is garbage collection, which -is essential-.  Other facilities that take
a lot of space in Poplog are the Common Lisp equivalent numbers (fractions,
complex numbers ...) and the C-based widget sets.

However both FORTH and C were conceived of as languages for -small- machines
and their role in the market place may be eroded as people realise that
machines are no longer small, but software packages are -big-, and need to be
written in languages that provide better means of constraining programmers.

Systems like POPLOG which provide -semantic- support intended for a variety of
languages would seem to have a discintct advantage over both FORTH and C.

Quote:
> Another major advantage of FORTH is access to the compilation mechanism.
> The components of : (the standard compiler) can be used to create special-
> ized mini compilers for specific tasks. For example, I have been using for
> several years a simple mini compiler FSM: that turns a state-transition
> table into a finite state machine. Recently I read an article (before
> submission to a journal) on mini compilers that produce optimized machine
> code for a target cpu, then download it for testing (this kind of thing
> enormously speeds embedded systems development and real-time programming).

Poplog ...

read more »



Sat, 16 Mar 1996 22:53:19 GMT  
 Threaded Interpretive Languages

        [ lots of stuff about POP-1, POP-2, ... POP-11 and FORTH deleted ]

Quote:

> The only snag here is that assembler is non-portable. The C-interface of
> POPLOG is to my mind preferable.

> Robin Popplestone.

Thank you for your spirited discussion of another little-known language.

It is obvious that you like it. Possibly the name appeals to you?  :-)

I note Chuck Moore did not name his creation "MOORTH" however...

--jvn



Sun, 17 Mar 1996 03:57:00 GMT  
 Threaded Interpretive Languages


Quote:
> Thank you for your spirited discussion of another little-known language.
> It is obvious that you like it. Possibly the name appeals to you?  :-)
> I note Chuck Moore did not name his creation "MOORTH" however...

Actually the language was originally called "Cowsel" that is "COntrolled
Working SpacE Language" - not a good name I admit. The eponymous garbage
collector was cribbed from LISP, but since interpretation of lists on the
British machines that even in 1964 were antique would have been inutterably
slow I employed a reverse polish internal form, initially interpreted.
Early in my existence in Edinburgh I did a covert implementation (we were all
supposed to use Algol 60), and managed to persuade people that being able to
change your program in seconds rather than hours was a Good Thing. The price
of acceptance by the boss (Donald Michie) was manifest when I returned from a
short holiday - the language was now called "POP", and I have had to live with
that ever since. Rod Burstall's daughters were particularly indignant - they
felt the successor should be called "Daddy-2".

Incidentally the latest RISC machines represent a return to aspects of the
earlier architectures in that access to main memory is now slow compared with
access to local memory....

Now I know that Brand Loyalty in computer languages is of a standard to make
a detergent manufacturer glow a fluorescent green, so it is something of a
waste of time to post on anything other than to the modest following of
comp.lang.pop, but actually people should know that the particular mix of
capabilities in the language they love, if it is unique, may have parallels
elsewhere which offer some advantages.

Robin Popplestone.



Sun, 17 Mar 1996 18:46:04 GMT  
 Threaded Interpretive Languages

Quote:
> Forth,  if I  understand  it rightly,  is not  tagged  (an
> advantage for systems applications) and not garbage collected.

It can't be tagged, since it is a single data type language (like BCPL),
and as you say, it is not GCed.

Quote:
> Moreover with a language that supports in-lining [like C++ (not my
> favourite by the way) or Haskell say] a big win is possible, since a
> small function may inline in less space than its call takes, and is of
> course faster. This is directly opposed to threaded-code, where by
> definition the small function -must- be called, since it may be
> redefined. Typically threaded code is useful for -debugging- but it is
> best converted into an unthreaded form for use in a module like a
> mailer where it will be normally used unchanged.

Actually this isn't true of Forth - although a service function can be
redefined, the old version is used by any client functions compiled
before the change. There have been experimental systems which do allow
redefinition, but the overheads aren't considered worthwhile in the
embedded systems market which Forth mainly addresses now. Some modern
Forths do have limited automatic inlining, and more usefully there are
rough analogues of C++'s "inline" keyword that can be used to imbed
sequences of instructions in the word currently being defined.

Quote:
> The only snag here is that assembler is non-portable. The
> C-interface of POPLOG is to my mind preferable.

Horses for courses, surely. Barring the odd fanatic (and some of them
can be *very* odd) Forth is used for imbedded systems - very machine
specific, and C needs libraries for some things that assembler can do
directly (e.g. accessing I/O ports on a non memory-mapped machine).
The C interface for Poplog is more useful for interfacing X etc:
no-one will use Pop to run a washing machine, after all.

Incidentally, since I doubt it will get a mention otherwise in a
mainly Unix/VMS forum, it may be worth mentioning that the structured
BASIC supplied with MS/DOS 5 and up is a threaded compiler: individual
lines are compiled (as the editor cursor leaves the line), and are
used by something analogous to the "inner interpreter" of early
Forths. The main advantages in this case are immediate syntax
checking, and the ability to resume the program after most edits.  A
matching true compiler is available for the finished version.

Scott



Sun, 17 Mar 1996 20:16:03 GMT  
 Threaded Interpretive Languages
The zeitgeist works in mysterious ways... Actually I can explain the
development in terms of putting together ideas that were current in the early
'60's. My computing career began c. 1963 when I tried to program the
Manchester Atlas to solve word problems in group theory. After a course in
Mathematical Logic, from Robin Gandy, my horizons broadened to include proof
in general. For that, I was advised that -the- Compiler Compiler was just the
job. Well, the Compiler Compiler (implemented for the Atlas) turned out to be
inadequate, it built beautiful data-structures when it parsed logic sentences
in the grammar I had defined, but it built them -on the stack-. This was fine
for generating code in the rather shallow way the CC did (no prolonged mulling
over register allocation....) but of course useless for logic - these
beautiful data-structures vanished before I could do anything with them,
leaving me with a permanent suspicion of languages that relied over much on
the stack as a data-store.

So the 1964 summer school on "Non-Numerical Computing" in Oxford came as
something of a revelation to me. Landin and Strachey were there, explaining
about LISP, Algol and CPL. The main ideas I took away seem to have been (a)
reverse polish as an intermediate form (b) garbage collection of list
structures and (c) the importance of function variables to support higher
order functions. Given that I was now in Leeds, with an antique Pegasus
computer, a minimal mix of these components seemed called for, which I called
"Cowsel". Some trivia included the use of "hd" and "tl" instead of "CAR" and
"CDR" taken from Woodward's list-processing library in Algol.

I suspect that Moore, in developing Forth, had less the needs of symbolic
computing in mind. That would seem to be the primary difference between POP-1
and Forth.

Subsequent evolution has been divergent between POP and FORTH. The
observation, that you can associate immediate action with -user defined-
symbols, giving a kind of -macro- was, I think, made by Rod Burstall, and used
to support an extension of POP-1 that allowed infix forms. (He drew on
experience with the implementation of CPL - he had worked for a period
with Strachey in Oxford). Thus one could embellish POP-1 with various flavours
of extension. We -institutionalised- this in POP-2 [demonstrated on-line in
IFIP 68 at Edinburgh] with a defined syntactic form that supported infix
notation, whereas FORTH has not. Essentially the POP-2 compiler incorporated
an operator precedence grammar driven by "immediate action" identifiers. To
this day this architecture shows. For example user-defined operators can have
a range of precedences - easy to arrange with that kind of grammar, but hard
if you use say YACC.

Subsequent work in Edinburgh tended to focus on developing purer functional
languages (Hope and SML) and logic languages (Prolog). POP was taken up as a
teaching language by Aaron Sloman, and developed into POP-11 and Poplog at
Sussex University.

Who gets the right blend of technology for the time is -always- an interesting
question. One of the reasons this conversation is conducted in English is that
Queen Elizabeth the First's ship designers dispensed with superstructure
superfluous in a ship that was meant to carry big guns and not soldiers. The
other is that said guns were mounted on quaint little 4-wheeled thingies that
supported a much higher firing rate than King Philip's Armada could match...

Robin



Sun, 17 Mar 1996 20:35:25 GMT  
 Threaded Interpretive Languages
Despite languishing at home with a cold, Robin's provocative posting
awakens the slumbering urge to contradict ....

Like Robin, I can't resist replying to this claim:

Quote:
> > Typical automated
> > measures of "program complexity" applied to FORTH code yield very low
> > indices even for programs I would regard as complex.

The natural conclusion to reach is that the measures are wrong.  FORTH
is a jolly interesting programming language but not especially
conducive to good programming style.  My own study program complexity
metrics lead me to believe that they are, to be frank, virtually
useless.  Only inside a tightly managed quality-control environment
could you hope to make good use of them.  [I'm happy to discuss at
length the (very serious) shortcomings of program metrics.  But I'll
spare the bandwidth, for the moment.]

Quote:
> Moreover with a language that supports  in-lining [like C++ (not my  favourite
> by the way) or Haskell say] a big win is possible, since a small function  may
> inline in less space  than its call  takes, and is of  course faster. This  is
> directly opposed  to threaded-code,  where by  definition the  small  function
> -must- be called, since it may be redefined. Typically threaded code is useful
> for -debugging- but it is best converted into an unthreaded form for use  in a
> module like a mailer where it will be normally used unchanged.

I'd like to point out the use of -plant_in_line- available in the next
release of the PLUG archive.  This enables you to transparently change
procedure calls into in-line code for simple functions.  The next release
should be available early next week.  Lots of new goodies.

Quote:
> For example, the POP-11:

> define flat(T);
>   define flat1(T);
>     if is_node(T) then flat1(left(T)); flat1(right(T));
>     else T
>     endif
>   enddefine;
>   [% flat1(T) %]
> enddefine;

> works by -stacking- the leaves of the tree in the inner -flat1- function.
> Rod Burstall's [% .... %] construction converts the stacked values to
> a list on the heap. This function is O(n), whereas an implementation
> using -append- would be O(n^2). And any O(n) implementation in a
> non-open-stack language is conceptually complicated by having to pass
> an argument in which the result can be accumulated.

There's an obvious quibble to be made here.  Here's an O(n) version
written without appeal to the open stack or accumulating arguments.
It works by use of a (more) global variable.

    vars G = conspair( undef, nil );
    define flat( T ) -> R;
        lvars p = G;
        define flat1( T );
            if T.is_node then
                flat1( node_left( T ) );
                flat1( node_right( T ) )
            else
                conspair( T, nil ) ->> back( p ) -> p
            endif
        enddefine;
        flat1( T );
        back( G ) -> R;
        nil -> back( G );
    enddefine;

Mind you, a mess like the above proves nothing except that you've eaten
too many Shreddies for breakfast.

Quote:
> > FORTH is incrementally compiled. The compilation mechanism is part of the
> > language and its components accessible to the programmer. This latter
> > feature distinguishes FORTH from all other languages I know. (Maybe Lisp
> > does it too? Don't know enough about it to say.) As a result, the user can
> > try something out as soon as it is defined. For example (a trivial one, to
> > be sure!) suppose we define a new FORTH subroutine (everything in FORTH is
> > a subroutine, called a "word", just as everything in C is a function):

> >         : *+   * +  ;  ( a b c -- b*c+a)

> POP-11 is rather more verbose. The direct equivalent:

>     define *+ (/*a,b,c*/); * + /* b*c + a */ enddefine;

This is, fair enough, the direct equivalent -- although the comments
rather clutter the clean lines of the original.  The relationship
is rather more obvious if one writes

    define *+; * + enddefine;

But, for the proud posssessors of the PLUG Source Code Archive, the
direct equivalent probably looks like this

    vars *+ = <<| * + |>> ;

[And for those lacklustre people who haven't got the PLUG SCA, it
would be possible to write
    vars *+ = nonop * <> nonop + ;
It just lacks the pizzaz of the SCA version.
]

Quote:
> > The colon ***is*** the compiler. It is a FORTH word that makes a new
> > dictionary entry with the name *+ .

> There are some disadvantages to this kind of approach. In fact Rod Burstall
> urged that we should use an abstract syntax for POP-2, rather than having
> the whole compiler driven by "immediate action" tokens.

And the omission of an abstract syntax must be ranked as the most serious
weakness of POP-11 as she currently exists.  Intriguingly, it is not
a very difficult technical problem to remediate.

Quote:
> Now here we come to the main issue. POP-1 -was- a small language. POP-2 larger
> and POP-11 has grown to be big by some people's standards, though smaller
> than Common Lisp systems. Now various languages have made much bigger market
> penetration because of being -at- the right time -in- the right place and
> -with- the right facilities. Some facilities at some times represent overkill,
> but they may be seen as essential later. The primary facility that comes to
> mind is garbage collection, which -is essential-.  Other facilities that take
> a lot of space in Poplog are the Common Lisp equivalent numbers (fractions,
> complex numbers ...) and the C-based widget sets.

I shall take the liberty of repeating my views on this interesting topic.
POP-11 is not an especially big programming language.  However, it has
evolved into a disorganised whole and this issue needs redressing.  For
example, how do you find out if an item is in a list?
    member( item, list )
But what if it was a string?
    locchar( item, 1, string )   /* watch out for type check! */
But what about a vector?
    for i in_vector vector do ... endfor
And an array?  And a closure?  And in the top N elements of the stack?
And an integer vector?  And a set?  And a queue?  And the stack of a
process?  And the fields of an arbitrary record?

The way to make the language smaller is to make it bigger(!).  We need
to impose a sensible hierarchy of types and then systematically implement
the operations to reflect that hierarchy.  Indeed, it was for this reason
that I implemented ObjectClass, in the hope that the provision of a
object-oriented system closely aligned with the POP-11 type system
would initiate this rationalisation.

Quote:
> However both FORTH and C were conceived of as languages for -small- machines
> and their role in the market place may be eroded as people realise that
> machines are no longer small, but software packages are -big-, and need to be
> written in languages that provide better means of constraining programmers.

> Systems like POPLOG which provide -semantic- support intended for a variety of
> languages would seem to have a discintct advantage over both FORTH and C.

Hear, hear!  I imagine that shared libraries will have an important role
here.  If operating systems provided shared library support for some of
the most commonly used symbolic language primitives (e.g. tagged
arbitrary precision arithmetic) then the overhead of running several
symbolic processing applications would be brought to a sensible level.

The large size of programming environments such as POPLOG can be seen
as mainly due to their duplication of low-leve computing facilities
that are provided in an inappropriate way.  For example, full arithmetic
is provided because of the inadequacy of machine-level arithmetic.
Equally, garbage collection is provided because of the inadequacy
of provided, standard store management routines.

[Incidentally, I concur with Robin's off-the-cuff remark that
conservative garbage collectors are inadequate.  I've closely
followed the reports on many conservative garbage collectors
and pathological cases are just too frequent to be acceptable.
Diagnostic libraries, such as Sentinel, are clearly the best
current option for engineers labouring their life away in skull-
numbing low-level languages such as C and C++.  (Wot?  No
secure automatic storage management?  No thanx!  This is the 1990's
you know.)]

Quote:
> The next release is coming out with a YACC style parser generator.

What?  First I've heard of it.  Sounds very interesting ... we want
to get our grabbers on it NOW!

Quote:
> > The above and related advantages are the chief reasons why FORTH users
> > would rather fight than switch.

> One knows the feeling...

This "fight vs switch" mentality is very damaging.  We should simply
use the best available technology for the job.  Sometimes that will be
a low-level language such as C++ or FORTH (or NEON or any of its
OO kin) but mostly it will be something high-level, with higher-order
procedures, proper lexical binding, proper arithmetic models,
a decent interactive development environment, full automatic, secure,
optimum storage management, powerful graphical development tools,
efficient compilation as well as efficient run-time, and the ability
to transparently move between programming paradigms when appropriate.  

We don't fight.  We merely say "find the alternative because we're
willing and able to switch to anything half as good."

Quote:
> Well... I managed to get the -tak- benchmark to run 6x -faster- than  C in
> POP-11 for a particular set of big arguments by writing:

>     memo_n(tak,3,1) -> tak;

> That is "replace tak by its memoised version - by the way it takes 3 arguments
> and returns one result". Now this is perhaps cheating. But is it?

Yes, it is cheating.  It is perfectly true that "memo_n" cannot be written
in C (well, it sort of can, but only very sort of).  But the purpose of
"tak" as a benchmark has always been to test raw procedure calling speed.
[Naturally, on system such as POPLOG it equally tests the speed of full
arithmetic addition, too.]  If a C-programmer wanted to make "tak" go
fast they might write a special purpose memoisation ...

read more »



Mon, 18 Mar 1996 01:31:50 GMT  
 Threaded Interpretive Languages

Quote:

>The zeitgeist works in mysterious ways...

        Ain't it the truth, Robin!? For instance, it's pretty obvious that
Forth and C were invented primarily to solve one and the same problem,
which was to transform the archaic, lugubrious human-oriented syntax of
the then-extant languages into a more machine-oriented, low-level compromise
syntax.

Quote:
>I suspect that Moore, in developing Forth, had less the needs of symbolic
>computing in mind. That would seem to be the primary difference between POP-1
>and Forth.

        Interesting in this regard is to compare Forth to Postcript,
the latter being more oriented towards symbolic computing, yet
differing from Forth in essentially only three respects:

        1) Addition of the /symbol data type.

        2) Metachar parsing forcing forth "+", for example, to be renamed
        postscript "plus".

        3) Temporary heap objects and garbage collection added to PS.

                =jax=
--



#SYSOP RCFB (303) 278-0364      # - Chuck Moore, live on Compuserve, 1986



Mon, 18 Mar 1996 01:42:30 GMT  
 Threaded Interpretive Languages

:       Interesting in this regard is to compare Forth to Postcript,
: the latter being more oriented towards symbolic computing, yet
: differing from Forth in essentially only three respects:

:       1) Addition of the /symbol data type.

:       2) Metachar parsing forcing forth "+", for example, to be renamed
:       Postscript "plus".

:       3) Temporary heap objects and garbage collection added to PS.

:               =jax=

i am still climbing that steep curve to forthdom, but i did a bit of
postscript before. i was wondering how the operator "bind" appears in
forth, i guess its one of those words i have yet to learn about.

--

                  fidonet#1:167/141     mtlnet#17:514/250



Mon, 18 Mar 1996 11:39:11 GMT  
 Threaded Interpretive Languages

|> i am still climbing that steep curve to forthdom, but i did a bit of
|> postscript before. i was wondering how the operator "bind" appears in
|> forth, i guess its one of those words i have yet to learn about.

I looked bind up in the red book and found out that it does what the
Forth compiler does, i.e., replace the names of the words with their
execution tokens. I.e., a Forth colon def is represented in a way that
a PS procedure would be after applying bind. If you want to have
something like the normal PS behaviour, you have to write the words in
the following way:

Instead of

: foo
 bar ;

: foo
 s" bar" evaluate ;

Of course, this would be very slow. Also, if you do a lot of words
like this, you would make a new defining word for them.

- anton
--
M. Anton Ertl                    Some things have to be seen to be believed



Mon, 18 Mar 1996 18:38:19 GMT  
 Threaded Interpretive Languages

Quote:
> i was wondering how the operator "bind" appears in
> forth, i guess its one of those words i have yet to learn about.

#_INCLUDE "disclaimer.ph" ;;; I don't know Postscript (yet!), and I'm not
                          ;;; a Forth guru

From a cursory reading of the Red Book, bind appears to replace the
string name of an operator by the value of that operator for all
operators in a definition which have already been defined, protecting
the definition from any changes in the operators used and improving
speed. Normal Forth does this for any definition compiled with the
defining " : " word: there is no way of redefining the words used in a
definition (i.e. you *can* change their definitions, but the old
version will be used in any words already using them). You can get the
effect by using an indirection mechanism (like function pointers in
C), but you have to do this explicitly. Definitely a language for
bottom-up programming!

(By the way, has everyone noticed that Sun Sparcs have a large Forth in
the boot ROMs, with graphics and networking? I have a fantasy that
somewhere out there there is a true believer who has never bothered to
boot Unix, but is happy to have the fastest FOrth workstation
around...)

Robin, the CPL you keep mentioning - is it the same as the (unfinished?)
ancestor of BCPL, and are there any books extant on it?

Scott



Mon, 18 Mar 1996 21:46:53 GMT  
 Threaded Interpretive Languages

Quote:

> |> postscript before. i was wondering how the operator "bind" appears in
> |> forth, i guess its one of those words i have yet to learn about.

> I looked bind up in the red book and found out that it does what the
> Forth compiler does, i.e., replace the names of the words with their
> execution tokens. I.e., a Forth colon def is represented in a way that
> a PS procedure would be after applying bind. If you want to have
> something like the normal PS behaviour, you have to write the words in
> the following way:

> Instead of

> : foo
>  bar ;

> : foo
>  s" bar" evaluate ;

> Of course, this would be very slow. Also, if you do a lot of words
> like this, you would make a new defining word for them.

A propos of this remark about the slowness of writing things as
strings and EVALUATEing them, it is nice to recall the posting on this
newsgroup last Spring (I think) advertising for a FORTH programmer
experienced in optimization. The ad was placed by Adobe Systems...

--jvn



Mon, 18 Mar 1996 21:41:29 GMT  
 Threaded Interpretive Languages

Quote:

>i am still climbing that steep curve to forthdom, but i did a bit of
>postscript before. i was wondering how the operator "bind" appears in
>forth, i guess its one of those words i have yet to learn about.

        The conceptual space occupied by PScript "bind" and "binddef"
are occupied in Forth by colon definitions

        : FOO DUP SWAP OVER ;

and CONSTANT and non-standard constructs like Dr. Noble's ALIAS.

                        =jax=
--



#SYSOP RCFB (303) 278-0364      # - Chuck Moore, live on Compuserve, 1986



Tue, 19 Mar 1996 01:40:14 GMT  
 Threaded Interpretive Languages

Quote:


>>The zeitgeist works in mysterious ways...

>    Ain't it the truth, Robin!? For instance, it's pretty obvious that
>Forth and C were invented primarily to solve one and the same problem,
>which was to transform the archaic, lugubrious human-oriented syntax of
>the then-extant languages into a more machine-oriented, low-level compromise
>syntax.

JAX, you know that Forth was developed to control telescopes, and
C was designed to support an operating system.  Those
sound like widely disparate problems to me!


Sat, 23 Mar 1996 08:34:44 GMT  
 Threaded Interpretive Languages

Quote:
>>The zeitgeist works in mysterious ways...
>     Ain't it the truth, Robin!? For instance, it's pretty obvious that
>    Forth and C were invented primarily to solve one and the same problem,
>     which was to transform the archaic, lugubrious human-oriented syntax of
>    the then-extant languages into a more machine-oriented, low-level
>    compromise syntax

True for Forth. But the syntax of C is not simple, just succinct.  "{" and
"}" happen to be -shorter- then "BEGIN" and "END" but they play the same kind
of syntactic role. Actually the syntax of C is, from the point of view of the
compiler-writer (and this point of view has some claim to being -objective-)
is unpleasantly -more- complex than that of Pascal, namely that in the
declaration of a variable, there is no connected bit of text which is the
-type- of the variable. E.g. in

    int A[6];

A is a vector of 6 integers, but the type information straddles the
identifier. In this respect, C makes the -wrong- extension of the syntax of
Algol 60/CPL and Pascal makes the right one.

Despite this, I happen, as a user, to -like- the syntax of C, so much so that
I have considered doing a version of POP with a C flavour.

What C and Forth do is in fact provide a suitably low-level -semantic-
view of the machine. As such they provide useful -target languages- for
higher level languages, as does the Poplog Virtual Machine, but at a higher
level (that is you are discouraged from seeing raw store). I have made a
little table comparing these:

GC = built-in garbage collector (this may or may not be a bonus - e.g. the
Glasgow Haskell compiler has its own ideas about tags and garbage which can
be matched by Poplog at a modest cost). INC = Incremental
definition/redefinition of program.

                Code Speed   Availability          Price        Size    GC INC
-----------------------------------------------------------------------------
C               excellent    near-universal       cheap       Modest   no  no

Poplog VM       good but      Unix&VMS - most     expensive    Big     yes yes
                poor floats  major architectures

Forth           poor?                             cheap?     Modest?  no   yes

Now, there are various gaps to close. How good can Forth code be made? Is
a built in garbage collector desirable?

Robin Popplestone.



Sat, 23 Mar 1996 20:45:15 GMT  
 Threaded Interpretive Languages

        [ stuff deleted ]

Quote:
> level (that is you are discouraged from seeing raw store). I have made a
> little table comparing these:

> GC = built-in garbage collector (this may or may not be a bonus - e.g. the
> Glasgow Haskell compiler has its own ideas about tags and garbage which can
> be matched by Poplog at a modest cost). INC = Incremental
> definition/redefinition of program.

>                 Code Speed   Availability          Price        Size    GC INC
> -----------------------------------------------------------------------------
> C               excellent    near-universal       cheap       Modest   no  no

> Poplog VM       good but      Unix&VMS - most     expensive    Big     yes yes
>                 poor floats  major architectures

> Forth           poor?                             cheap?     Modest?  no   yes

> Now, there are various gaps to close. How good can Forth code be made? Is
> a built in garbage collector desirable?

        FORTH generally does not need garbage collection because all
        memory allocation is under the user's control. That is, FORTH
        does not often use linked lists (other than the dictionary) and
        if a user defines a LL, then it is his responsibility to see that
        the trash is taken out.

        What about "code quality"? There are of course many measures of
        this: speed, succinctness, clarity, maintainability, ease of
        reading, ease of programming, debugging, complexity, etc.

        Following the Biblical injunction ("...and the last shall be first")
        let me address complexity. By most measures, FORTH programs that do
        fancy things exhibit low- to zero complexity. (An article in DDJ
        surveyed this some years ago.) Perhaps more modern measures have
        been developed that do not bomb out on FORTH, but I do not know
        about them. The reason is that many subtle and interesting FORTH
        programs do everything with defining words, so the business end
        gets hidden in the DOES> ... ; portion (which is often CODEd).
        Another reason for apparent lack of complexity is that the FORTH
        philosophy avoids decisions, letting execution take its place.
        That is, the compiler has nothing to decide when IF...ELSE...THEN
        DO...LOOP, BEGIN...UNTIL or BEGIN...WHILE...REPEAT are encountered
        in the input stream. These words are IMMEDIATE and execute the ap-
        propriate actions to install the branching primitives. Real FORTH
        programmers (and despite my 8 years' experience and authorship of
        a FORTH book I do not yet presume to call myself one, yet) tend
        to use this power so naturally that their programs appear branch-
        less, hence devoid of complexity. An example is a typical FORTH
        assembler. Complete assemblers for CISC chips are often no more
        than a few hundred lines long, and compile to a couple of kilo-
        bytes, depending on the rationality of the machine-language.

        What about debugging? Well all incrementally compiled languages
        that can be tested interactively debug quickly. I have used
        QuickBasic for that reason (and interpreted BASIC before that
        in preference to fortran). But FORTH is easier than anything else
        I have tried, including single-stepping de{*filter*}s, etc. etc.

        Ease of programming: depends on the task. If I have thought it
        out and decomposed it into orthogonal sub-tasks, then it is
        usually pretty quick. A case in point (that my book treats in
        detail, including false steps) is solving linear equations:

        Gaussian elimination with pivoting requires triangularizing
        the matrix in place, then back-solving. Triangularizing has
        several steps--finding the pivot element, transposing rows,
        and eliminating leading elements (by combining rows). Each of
        these steps is given a name and tested individually. The
        entire job takes very little time--perhaps a couple of hours
        starting from scratch.

        What about ease of reading/maintainability? The old canard that
        FORTH is "write-only" holds mainly for undocumented code with
        poorly chosen word-names, and poorly factored definitions. When
        programmers take the trouble with comments, names, factoring
        layout, etc. then FORTH can be easy to read. Perhaps the biggest
        problem (assuming the above conditions are met) lies in the fact
        that FORTH is so freely extensible that programmers often develop
        idiosyncratic styles and conventions that convey little to others.
        That is, one man's self-documenting code is often another's
        heiroglyphics. This is no different, really, from the professor
        who, having forgotten how little he once knew, says "Obviously..."
        and the cure is the same: lots and lots of low-level explanation.

        Clarity is in the mind of the beholder. But FORTH tends to short
        subroutines that can generally be understood at a glance. Good
        naming helps, too. Thus my program for linear equations reads

                : solve   setup  triangularize  backsolve  ;

        FORTH excels at succinctness, as noted above. For example, my
        little FORmula TRANslator, that allows embedded formulas in
        definitions to be translated on the fly to FORTH, as in

                : test  F"  a = (b+c)/(c-d) - COSH(pi*a) "  ;

        compiles to about 7 Kbytes of which 1 Kb is a buffer; another
        0.5 K or so is the function library. Amazingly, the
        source is only some 450 lines of (heavily commented!) code.

        Finally, speed: high level FORTH is typically, 5x to 10x slower
        than C compiled with an optimizing compiler, depending on the
        method of threading. However, many FORTHs nowadays come with
        some form of inline optimizer that will convert selected words
        to inlined machine code. Certainly the FORTH I use does this.
        Although said code is not super-optimized, it generally runs
        within 2x of pretty good machine code. I have had long experience
        at hand-optimizing machine language (since 1961) so my comparisons
        (for both Intel and Motorola families) are probably good rules of
        thumb for scalar processors.

        Some FORTHs now compile directly to optimized machine code, giving
        the best of all possible worlds (except that they then lose the
        memory parsimony that has always been FORTH's hallmark--personally
        I prefer the peephole optimizing of the preceding paragraph).

        I hope you find these comments responsive.  --jvn
--
Julian V. Noble



Sat, 23 Mar 1996 22:39:00 GMT  
 
 [ 27 post ]  Go to page: [1] [2]

 Relevant Pages 

1. TIL - Threaded Interpretive Languages

2. Threaded Interpretive Languages

3. Defining Pop11 (Was: Re: Threaded Interpretive Languages)

4. Defining Pop11 (Was: Re: Threaded Interpretive Languages)

5. Threaded Interpretive Languages

6. Dynamic interpretive languages

7. Dynamic interpretive languages

8. Looking for interpretive Ada for teaching environment

9. using Python as a interpretive backend?

10. Threads creating threads creating threads...

11. thread, threading, mutex modules and non-threading interpreters

12. Threaded Interpreted Languages

 

 
Powered by phpBB® Forum Software