# Oberon et al

## Soren Renner — 2003-01-22 17:53:47

    I am glad to see Oberon mentioned in Professor v. T's posts. I would like

    to say again that I have written a little toy version of a Joy-like

    language (called "toy"). I would not be indifferent if someone were to

    ask to look at it. I am about to get a new box that can run Bluebottle (the

    new Oberon-based OS, now completely open-source) and start programming

    again. It would not be necessary, in order to show "toy" to one of you,

    that he or she be running Bluebottle, or Native Oberon as an OS. LNO (Linux Native Oberon) would be sufficient.

    To switch away from C as the ground upon which the programming language

    castle is erected is a major step. But I think it is necessary. At least,

    I cannot believe otherwise, or act as though I did. Building a full

    Joy version in Oberon would be a large project, but one I could tackle,

    I think. If I have struck a chord in any of you, however faint,please

    listen to it. I do not ask that you switch to Oberon for your own

    programming, or that you become advocates; only that some one of you

    (preferably, of course, Manfred van Thun) installs LNO, NO, or Bluebottle

    for the purpose of looking at what I have done, and what I will (given

    minimal encouragement) do. Thank you in advance,

    Soren Renner

## Manfred von Thun — 2003-01-24 02:16:23

    On Wed, 22 Jan 2003, Soren Renner wrote:

     > To switch away from C as the ground upon which the programming language

    > castle is erected is a major step. But I think it is necessary. At least,

    > I cannot believe otherwise, or act as though I did. Building a full

    > Joy version in Oberon would be a large project, but one I could tackle,

    > I think.

     I would urge you to work on a small version first. You might look at

    the main Joy page, Part 3 "Miscellaneous", has links to a mini-Joy

    written in Pascal, 550 lines or so. Could give you some useful hints.

    You won't need the garbage collector, of course. Also, this implementa

    tion needs to read the library in two passes: once for the names only,

    and once for the actual definitions. I would not do that again.

    When you have written a small version, I'd be glad to put it together

    with a demo input and output in the same "Miscellaneous" collection.

    Then start afresh on a fuller version.

     >                                                        some one of you

    > (preferably, of course, Manfred van Thun) installs LNO, NO, or Bluebottle

    > for the purpose of looking at what I have done, and what I will (given

    > minimal encouragement) do. Thank you in advance,

     Well, I don't know what these things are, how big they are, and how

    portable they are.  They might need to be put into the concatenative

    files area. Or just a link from the Joy page to their home. We'll see when

    the time comes.

    But do a little version first, with a demo.

      - Manfred

## falvosa <kc5tja@arrl.net> — 2003-02-28 07:52:56

    > > (preferably, of course, Manfred van Thun) installs LNO, NO, or

     Bluebottle

     > > for the purpose of looking at what I have done, and what I will

     (given

     > > minimal encouragement) do. Thank you in advance,

    >

    > Well, I don't know what these things are, how big they are, and how

    > portable they are.  They might need to be put into the concatenative

    > files area. Or just a link from the Joy page to their home. We'll

     see when

     > the time comes.

     It's been 3 years since I last was here, and a lot has happened.  I'm

    still catching up.

    Oberon is a Pascal-like programming language, with garbage collection,

    run-time performance just a hair short of C (because of run-time

    checks; if you turn off the type safety and run-time checks, the code

    is as fast as C, easily), and a HECK of a lot easier to understand

    syntax.

    LNO is the Linux Native Oberon package.  It's an implementation of

    Oberon System 3 for Linux, that runs under X11.

    However, you don't necessarily need to use the Oberon System to

    program in Oberon.  For example, I write useful Linux software using

    oo2c, a stand-alone Oberon environment for Linux that produces native

    Linux executables.  If the Oberon System and its user interface is

    off-putting to you, then oo2c sounds like a better solution.

    The sole disadvantage of Oberon for the time being is that it lacks a

    truely standard run-time library (e.g., it has no stdio equivalent).

    The Oakwood conventions are supposed to fill that role, and largely do

    for most programs, but it's not complete.  Moreover, environments such

    as OO2C will sometimes elect to use different module names for the

    Oakwood components.  For example Oakwood's Out module is OakOut in

    OO2C.  Fortunately, porting is very, very easy -- you can use module

    aliases:

        IMPORT Out := OakOut, ..etc...

    Despite the incompleteness of the Oakwood modules, they should be way

    more than necessary to implement a language with, especially for Joy.

    --

    Samuel A. Falvo II

## phimvt@lurac.latrobe.edu.au — 2003-03-12 05:14:16

    On Fri, 28 Feb 2003, falvosa <kc5tja@...> wrote:

    [.. apropos writing a Joy in Oberon ..]

    > Oberon is a Pascal-like programming language, with garbage collection,

    > run-time performance just a hair short of C (because of run-time

    > checks; if you turn off the type safety and run-time checks, the code

    > is as fast as C, easily), and a HECK of a lot easier to understand

    > syntax.

    Coming from Wirth, it just has to be a very clean language. As you

    know, I have programmed for years in Pascal.

    > LNO is the Linux Native Oberon package.  It's an implementation of

    > Oberon System 3 for Linux, that runs under X11.

    I take it that this means not many potential Joy users could

    switch to this system so easily.

    > However, you don't necessarily need to use the Oberon System to

    > program in Oberon.  For example, I write useful Linux software using

    > oo2c, a stand-alone Oberon environment for Linux that produces native

    > Linux executables.  If the Oberon System and its user interface is

    > off-putting to you, then oo2c sounds like a better solution.

    On the other hand, this would be far more attractive for potential

    Joy users. Still, even getting the compiler running would seem

    to be no mean feat. I also noticed that it uses the same Boehm

    garbage collector as John Cowan's Joy interpreter does. At any

    rate, the Oberon compiler would be several orders of magnitude

    larger than the Joy interpreter

    [..more on Oberon implementations..]

    Thank you for all this, especially the oo2c implementation was quite

    new to me.

    I do look forward to seeing and at least reading a Joy

    interpreter written in Oberon.

      - Manfred

## Samuel Falvo — 2003-03-12 09:18:57

    > Coming from Wirth, it just has to be a very clean language. As you

    > know, I have programmed for years in Pascal.

     I haven't.  Personally, I can't stand Pascal as a language.  I can't put my

    finger on it, but it seems very limiting to me.  I've never had any experience

    with Modula-2, but from what I've seen of it, it looks like it was much, much

    better.  But trying Oberon was a major eye-opener for me, and I will try hard

    to write my future software in either Forth or Oberon whenever possible.

    I was even considering developing a shareware application for PalmOS using

    Oberon, though that will require a custom-made compiler.  I was going to have

    it compile to a set of bytecodes optimized for run-time native code generation

    for best speed, with the core virtual machine itself written in Forth.  This

    would enable the same binary modules to run either on x86 or PalmOS, with full

    data interoperability as well.

    However, Forth itself is also a candidate for this task.  However, I'm also

    concerned that people will be discouraged from writing plug-in modules for the

    product if I were to write it in Forth... :/

     > > LNO is the Linux Native Oberon package.  It's an implementation of

    > > Oberon System 3 for Linux, that runs under X11.

    >

    > I take it that this means not many potential Joy users could

    > switch to this system so easily.

     I don't understand what you're trying to convey here.  Can you clarify?

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## John Cowan — 2003-03-12 17:38:15

    Samuel Falvo scripsit:

     > I haven't.  Personally, I can't stand Pascal as a language.  I can't put my

    > finger on it, but it seems very limiting to me.

     See Brian Kernighan's "Why Pascal Is Not My Favorite Programming Language"

    at http://www.lysator.liu.se/c/bwk-on-pascal.html among other places.

    --

    John Cowan  jcowan@...  www.reutershealth.com  www.ccil.org/~cowan

    Promises become binding when there is a meeting of the minds and consideration

    is exchanged. So it was at King's Bench in common law England; so it was

    under the common law in the American colonies; so it was through more than

    two centuries of jurisprudence in this country; and so it is today.

           --_Specht v. Netscape_

## Samuel Falvo — 2003-03-12 19:49:42

    > > I haven't.  Personally, I can't stand Pascal as a language.  I can't put my

    > > finger on it, but it seems very limiting to me.

    >

    > See Brian Kernighan's "Why Pascal Is Not My Favorite Programming Language"

    > at http://www.lysator.liu.se/c/bwk-on-pascal.html among other places.

     I have, but his views are not only orthogonal to mine, but even somewhat

    offensive, because he leaves it at that.  He never considers Modula-2 nor

    Oberon as alternative programming languages, which leads me to believe that his

    feelings towards these languages are precisely the same as for Pascal, which is

    patently false.

    Also, if I remember correctly, he brings up a number of stylistic issues (which

    do apply to Modula-2 and Oberon) which I do not agree with philosophically,

    especially in light of studies conducted comparing C to Pascal-like languages

    and my own personal experiences.  Many of the issues he claims as advantages

    have been proven to be major impediments to C and, in particular, maintenance

    of programs written in C.  As a programmer who's worked with C for almost two

    decades, I've been bitten by C, and even its successor C++, more times than I

    can remember.  When I discovered Oberon for the first time, I had a bit of a

    love/hate relationship because I wasn't used to its *extremely* strong

    type-checking.  But now I can't think of any other way I'd like to program.  I

    still love Forth, but I sure wish it had type checking at least as strong as

    Oberon's now.  In fact, come to think of it, Oberon is simple enough a language

    to actually implement in-place in Forth itself.  I might consider playing

    around with this concept in the future; it could actually be the solution to my

    third-party plug-in developers dilemma.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## John Cowan — 2003-03-12 20:52:40

    Samuel Falvo scripsit:

     > I have, but his views are not only orthogonal to mine, but even somewhat

    > offensive, because he leaves it at that.  He never considers Modula-2 nor

    > Oberon as alternative programming languages, which leads me to believe that his

    > feelings towards these languages are precisely the same as for Pascal, which is

    > patently false.

     Note the date.  Kernighan's review was written in 1981, at which time Modula-2

    was one year old and Oberon did not exist.

     > I still love Forth, but I sure wish it had type checking at least as strong as

    > Oberon's now.

     Check out strongForth at http://home.t-online.de/home/s.becher/forth/

    I don't know much about it, but it looks like what you want.

    --

    Schlingt dreifach einen Kreis vom dies! || John Cowan <jcowan@...>

    Schliesst euer Aug vor heiliger Schau,  || http://www.reutershealth.com

    Denn er genoss vom Honig-Tau,           || http://www.ccil.org/~cowan

    Und trank die Milch vom Paradies.            -- Coleridge (tr. Politzer)

## wtanksleyjr@cox.net — 2003-03-12 22:07:19

    From: Samuel Falvo <falvosa@...>

     >Oberon's now.  In fact, come to think of it,

    >Oberon is simple enough a language to actually

    >implement in-place in Forth itself.

     It's worth noting that a nice subset of Oberon is

    distributed with the parser generator "Gray" (or

    was that "Grey", I can never remember), which is

    written in and for Forth. Since you're writing your

    own Forth, you could easily engineer Gray alongside

    your Forth to be able to help you output code.

    Concatenative folks: Gray is interesting in that it

    uses Forth's ability to introspect the currently-active

    source code. Thus, you can define a parser and directly

    use it in the same source file in which it was defined.

    This ability to introspect currently active source is

    not entirely unique to concatenative languages (Lisp has

    it as well), but it's only possible to the extent that

    a language is NOT applicative. That is, you can only

    plausibly parse source code which hasn't yet been parsed

    by the compiler, which means that a function can't parse

    its own arguments. Lisp gets around this by defining three

    different types of functions: ordinary, macros, and reader

    macros. Forth only needs two types to handle all the same

    things.

    It's interesting that although concatenativity allows

    this introspection, actually _doing_ the

    introspection destroys concatenativity, since it makes

    the function depend on what appears after it in the

    source text. It's therefore very interesting that

    common practice in Forth frowns upon using the

    introspection capabilities.

     >Samuel A. Falvo II

     -Billy

## Samuel Falvo — 2003-03-12 22:31:12

    > Note the date.  Kernighan's review was written in 1981, at which time

    > Modula-2

    > was one year old and Oberon did not exist.

     Exactly my point.  He has failed to revisit his position with respect to this,

    which leaves a nasty aftertaste in my mouth.  Most authors who publish such

    opinion pieces usually try to periodically update their experiences and report

    on them.  For example, Frederick Brooks, upon republishing the Mythical Man

    Month, has a whole new section in the book on his experiences since the first

    publication.  Many of his ideas have been confirmed, many have been proven

    false, and he reports on them accordingly.  And then there's me -- I really

    dislike Pascal, but I absolutely love Oberon.

    I'd like to see Kernighan do the same with respect to Oberon.

     > > I still love Forth, but I sure wish it had type checking at least as strong

    > as

    > > Oberon's now.

    >

    > Check out strongForth at http://home.t-online.de/home/s.becher/forth/

    > I don't know much about it, but it looks like what you want.

     The heart is in the right place, but the mechanism and details aren't quite

    there yet.  Billy Tanksley and I are constantly discussing this Forth

    implementation, its limitations, and its advantages.  Its biggest limitation is

    its lack of support for aggregate data types and dynamic memory management

    (automatically managed or otherwise).

    What I'd like to see is a datatyping mechanism that borrows heavily from

    Haskell/ML data types, since they are the simplest typing system I've ever seen

    (though it takes a while to wrap your mind around them, as it did for me).  For

    example, given a hypothetical infix functional language:

    datatype SceneList =

       EmptyList

     | SceneNode( object: SceneObject; next: SceneList );

    datatype SceneObject =

       EmptyScene

     | AggregateObject( left, top: integer; children: SceneList )

     | Label( left, top: integer; text: String )

     | Line( left, top, right, bottom: integer )

     | Box( left, top, width, height: integer );

    The single statement above creates a whole type hierarchy, without all the

    overhead of a full-blown object run-time environment.  The types declared are,

    of course, themselves constructor functions.

    A constructor function is defined as a function that assembles, or constructs,

    its parameters into a single object instance.  A decomposer (to distinguish it

    from the overloaded term destructor) does the reverse.  So, for example, to

    build a scene graph using applicative notation, we can do this:

    LET myLabel := Label( 0, 0, "Hello world!" ) IN

        myGraph := AggregateObject( 0, 0,

                    SceneNode( myLabel,

                    SceneNode( Box( -2, -2, Width(myLabel)+4, Height(myLabel)+4 ),

                    EmptyList )));

    It is interesting to note that the compiler, despite the applicative notation,

    knows entirely how to construct this structure statically in memory, because it

    knows what a constructor is versus a normal function.  Width() and Height()

    would presumably be functions that can execute at compile-time, if enough

    compile-time knowledge was known.  If not, the statement would have to be done

    at run-time.  But, I digress.

    In most applicative languages, the decomposer also has the same name as its

    constructor.  So something like this:

      Width( Label( leftEdge, topEdge, string ) ) := FONT_WIDTH * lengthOf( string

    );

    lets the function Width access individual elements of the object.  Most

    languages even support a don't care construct:

      Width( Label( _, _, string ) ) := FONT_WIDTH * lengthOf( string );

    My "Ideal Forth" version of this would construct the scene graph in a manner

    not unlike the following:

                                    EmptyList ( e )

                   S" Hello world!" 0 0 Label ( e label )

    DUP DUP Width SWAP Height -2 -2 2SWAP Box ( e label box )

                               >R SceneNode R> ( node box )

                                     SceneNode ( node )

                          0 0 AggregateObject ( agg )

    : Width ( label -- width )

      ~Label NIP NIP LengthOf FONT_WIDTH * ;

    Note how I use ~Label as the word for decomposing Label.

    My proposed syntax doesn't address how to declare the existance of these types

    either.  I'm still pondering over that, but this is what I have so far:

    TYPE SceneList

      TYPE EmptyList --> SceneList

      TYPE SceneNode --> SceneList

      << SceneObject SceneNode >> SceneNode

    TYPE SceneObject

      TYPE EmptyScene --> SceneObject

      TYPE AggregateObject --> SceneObject

      TYPE Label --> SceneObject

      TYPE Line --> SceneObject

      TYPE Box --> SceneObject

      << INT INT SceneList >> AggregateObject

      << INT INT STRING >> Label

      << INT INT INT INT >> Line

      << INT INT INT INT >> Box

    Here, TYPE defines a new type descriptor, a constructor primitive, AND a

    decomposer primitive.  This requires that the host Forth environment support

    programmatically created words at run-time (which none that I'm aware of do;

    the closest you can get is very creative use of EVALUATE in ANSI Forth).  -->

    takes the last defined type and updates its "is-a" pointer to point to the

    specified data type. << is a word that interprets the given type ID list to

    build the "contents" of the data type (>> is not an actual Forth word, but

    instead just a delimiter, similar to -- in Becher's StrongForth's type

    signatures), then parses the next word to update the relavent type descriptor's

    "contents" field.  INT and STRING are special type descriptors that represent

    primitive data types (non-garbage collectable).

    It's still a bit verbose for me, but it establishes everything I could need for

    a good type system.  My big quandary is that what appears between << and >>

    aren't self-documenting, though the remainder of it is nicely telegraphic for

    me.  It does support, however, efficient garbage collection, since even a naive

    Forth compiler will then know which fields are or are not references to other

    objects at the time the type descriptors are laid down in memory.

    As a possible syntactical optimization, we can have << also define its own

    type.  For example:

      TYPE SceneList

      << >> EmptyList --> SceneList

      << SceneObject SceneList >> SceneNode --> SceneList

    I think this is too visually cluttered though.  It also prevents the use of

    forward-declared types to handle circular references (e.g., where a SceneNode

    references a SceneObject, and that same SceneObject references a SceneNode.  In

    this case, you must TYPE both before you declare the contents of each type).

    Yes, I realize that TYPE is already allocated for use in Forth.  But I didn't

    want to constantly type DATATYPE throughout the whole e-mail.  :)

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## Steven Shaw — 2003-03-13 12:19:56

    > See Brian Kernighan's "Why Pascal Is Not My Favorite Programming Language"

    > at http://www.lysator.liu.se/c/bwk-on-pascal.html among other places.

     Thank goodness many of the criticisms levelled against Pascal don't apply to

    successors like Modula-2, Modula-3, Oberon, Oberon-2, and Component Pascal.

    Even Brian's involved with a new programming language which borrows from

    Pascal: http://www.vitanuova.com/inferno/papers/descent.html. So it couldn't

    have been all that bad :-).

    Steve.

## John Cowan — 2003-03-13 13:57:52

    Steven Shaw scripsit:

     > Even Brian's involved with a new programming language which borrows from

    > Pascal: http://www.vitanuova.com/inferno/papers/descent.html. So it couldn't

    > have been all that bad :-).

     In fact, his involvement apparently is limited to writing that paper, and

    the Pascal influence is limited to ":=" for assignment and the syntax of

    declarations.

    --

    John Cowan        http://www.ccil.org/~cowan          jcowan@...

    Please leave your values        |       Check your assumptions.  In fact,

       at the front desk.           |          check your assumptions at the door.

         --sign in Paris hotel      |            --Cordelia Vorkosigan

## Steven Shaw — 2003-03-13 16:19:20

    > > Even Brian's involved with a new programming language which borrows from

    > > Pascal: http://www.vitanuova.com/inferno/papers/descent.html. So it

     couldn't

     > > have been all that bad :-).

    >

    > In fact, his involvement apparently is limited to writing that paper, and

    > the Pascal influence is limited to ":=" for assignment and the syntax of

    > declarations.

     A crucial pascalism :-).

## Samuel Falvo — 2003-03-13 20:58:21

    > Even Brian's involved with a new programming language which borrows from

    > Pascal: http://www.vitanuova.com/inferno/papers/descent.html. So it couldn't

    > have been all that bad :-).

     I wasn't aware of this!  I will have to check this out.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## Samuel Falvo — 2003-03-13 22:36:17

    > > Even Brian's involved with a new programming language which borrows from

    > > Pascal: http://www.vitanuova.com/inferno/papers/descent.html. So it

    > couldn't

    > > have been all that bad :-).

    >

    > In fact, his involvement apparently is limited to writing that paper, and

    > the Pascal influence is limited to ":=" for assignment and the syntax of

    > declarations.

     Oh man ... oh man ... I don't know what to make of this language.  It

    apparently combines the worst syntactical elements of C and the worst

    syntactical elements of Haskell (actually CSP, from which Haskell is also

    derived from), and mish-mashes it all together into a language where even the

    Hello World example on the page leaves the reader curious as to when the pain

    and suffering will end.

    That is an abysmal programming language.  I'll take ActiveOberon or just plain

    Haskell over this *any* day of the week.

    Wow.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## phimvt@lurac.latrobe.edu.au — 2003-03-14 05:38:37

    On Wed, 12 Mar 2003, Samuel Falvo wrote:

     > > Coming from Wirth, it just has to be a very clean language. As you

    > > know, I have programmed for years in Pascal.

    >

    > I haven't.  Personally, I can't stand Pascal as a language.  I can't put my

    > finger on it, but it seems very limiting to me.  I've never had any experience

    > with Modula-2, but from what I've seen of it, it looks like it was much, much

    > better.  But trying Oberon was a major eye-opener for me, and I will try hard

    > to write my future software in either Forth or Oberon whenever possible.

     When I started teaching myself programming, we had a DEC10 and as

    languages we had Fortran, Cobol, Basic, Focal, Algol60, Snobol, Lisp,

    Bliss and an early Pascal. After a very brief exposure to Basic and Focal

    and a quite lengthy one to Algol60, I got hooked on Pascal in part

    because DEC was using it as their systems programming language. And

    indeed they did provide an excellent Pascal compiler which implemented

    *REAL* Pascal. I soon learned how to use local procedures as parameters

    in recursive calls to provide continuations in backtracking programs.

    Our Computer Science Department was at that time running a Pyramid

    and later a Sun, and they were teaching Pascal on those. All my

    backtracking programs did work on those machines too. When I was

    asked to do several years of teaching for them, I was able to use

    Pascal throughout. But often my students complained "it does not work

    on my micro.." Well, the cheap Pascals never bothered about maintaining

    the static links (or displays) to pass on local environments.

    Indeed, the use of local procedures as parameters in recursive

    calls appears to be a sort of black art, and I seem to be one

    of its few practitioners. See Chapter 8 "Second Order Recursion"

    on my Pascal page:

         http://www.latrobe.edu.au/philosophy/phimvt/s00bok.html

    and then Chapters 9 10 11 15 16 20 for some applications.

    I did note that the p2c utility cannot handle this sort of thing,

    and I am told that Modula2 does not allow it either, and as

    far as I can tell, Oberon also does not allow it. But I am

    heartened to hear that Modula3 does allow it, and the new Gnu

    Pascal also does. I don't know about the newer Oberons.

    But all this is quite irrelevant for an implementation of

    Joy in Oberon, because there is no backtracking involved.

    However, if anybody is thinking about a Joy-ified Prolog,

    do keep this backtracking technique in mind.

    [.. a propos LNO, the Linux Native Oberon 3 to run under X11 ..]

     > > I take it that this means not many potential Joy users could

    > > switch to this system so easily.

    >

    > I don't understand what you're trying to convey here.  Can you clarify?

     I meant something very simple actually, sorry if it wasn't clear.

    Many users either have C already or at least can get one easily

    and it will run on anything. Unless I misunderstand what you

    said, many potential users could not switch to Linux under X11

    - because they are running something else, or they have no

    control over what operating system is running.

      - Manfred

## Samuel Falvo — 2003-03-14 07:53:09

    > I did note that the p2c utility cannot handle this sort of thing,

    > and I am told that Modula2 does not allow it either, and as

    > far as I can tell, Oberon also does not allow it. But I am

    > heartened to hear that Modula3 does allow it, and the new Gnu

    > Pascal also does. I don't know about the newer Oberons.

     I am not certain that Oberon forbids passing local procedures as parameters.

    If it's used purely within the scope of its containing procedure, it should be

    valid to do so.

    However, what might be illegal is passing a reference to an inner procedure to

    ANOTHER outer procedure.  This would crash the system if it were allowed to

    happen, because the stack frames would not be properly constructed on the call

    stack.

     > But all this is quite irrelevant for an implementation of

    > Joy in Oberon, because there is no backtracking involved.

    > However, if anybody is thinking about a Joy-ified Prolog,

    > do keep this backtracking technique in mind.

     I have implemented backtracking in Forth using very few lines of code.  Forth

    makes this possible because it exposes the return stack as a first-class,

    programmer-accessible object.

     > I meant something very simple actually, sorry if it wasn't clear.

    > Many users either have C already or at least can get one easily

    > and it will run on anything. Unless I misunderstand what you

    > said, many potential users could not switch to Linux under X11

    > - because they are running something else, or they have no

    > control over what operating system is running.

     This is what I *thought* you meant, but I wasn't quite sure.  To this, I agree.

     Nonetheless, oo2c is, or at least should be, relatively platform independent

    -- it is an Oberon to C compiler, which has the convenience of automatically

    invoking the C compiler for you.

    Also, Oberon System 3 is also available for Windows and several other

    platforms.  There's also an Oberon V4, and now there's Bluebottle, which is an

    implementation of ActiveOberon.  I'm not sure if Bluebottle is ported to

    Windows or Linux, but I do know that it runs on x86 PCs natively as its own

    operating system.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## John Cowan — 2003-03-14 12:01:47

    phimvt@... scripsit:

     > Indeed, the use of local procedures as parameters in recursive

    > calls appears to be a sort of black art, and I seem to be one

    > of its few practitioners.

     In Pascal, I suppose you mean.  Of course the entire Lisp (and especially

    Scheme) community practices this art with abandon, and doesn't consider

    it black.  In Scheme, furthermore, you can return a local procedure as

    the value of one of its enclosing procedures.

    The GNU dialect of C allows local procedures and procedure arguments,

    but ANSI C does not.

    --

    John Cowan           http://www.ccil.org/~cowan              cowan@...

    To say that Bilbo's breath was taken away is no description at all.  There

    are no words left to express his staggerment, since Men changed the language

    that they learned of elves in the days when all the world was wonderful.

            --_The Hobbit_

## John Cowan — 2003-03-14 12:03:27

    Samuel Falvo scripsit:

     > I have implemented backtracking in Forth using very few lines of code.  Forth

    > makes this possible because it exposes the return stack as a first-class,

    > programmer-accessible object.

     I think, though, that that is not ANS FORTH compliant; no non-primitive

    word can have a net effect on the return stack.  In particular, I am

    certain that the idiom "r> drop exit" is not ANS FORTH.

    --

    John Cowan           http://www.ccil.org/~cowan              cowan@...

    To say that Bilbo's breath was taken away is no description at all.  There

    are no words left to express his staggerment, since Men changed the language

    that they learned of elves in the days when all the world was wonderful.

            --_The Hobbit_

## Samuel Falvo — 2003-03-14 16:41:46

    > In Pascal, I suppose you mean.  Of course the entire Lisp (and especially

    > Scheme) community practices this art with abandon, and doesn't consider

    > it black.  In Scheme, furthermore, you can return a local procedure as

    > the value of one of its enclosing procedures.

     While this may be true, it's generally not advocated in Lisp programming.  Lisp

    programmers generally tend to stick with more traditional, functional

    programming techniques, while Scheme programmers are more cutting edge.

    Indeed, Scheme came about primarily because they were unhappy with the

    doggedness of the Lisp programming community.

    The other thing to consider is that Lisp and Scheme uses a form of local

    variable binding where returning a function is like returning an object with a

    single method (a closure).  It's not lexical binding, I think they call it

    dynamic binding or something like that.  Anyway, Oberon uses more traditional,

    lexical binding.  I'm rather surprised to hear that Pascal uses dynamic

    binding, for otherwise it could not support passing inner procedures as

    parameters to other outer procedures, and actually have the system work.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## Samuel Falvo — 2003-03-14 17:25:20

    > I think, though, that that is not ANS FORTH compliant; no non-primitive

    > word can have a net effect on the return stack.  In particular, I am

    > certain that the idiom "r> drop exit" is not ANS FORTH.

     Without giving you exceedingly uninteresting details, my feelings towards ANSI

    Forth are not favorable.  ANSI Forth made a lot of decisions that lean towards

    very conventional methods of programming which patently do not take advantage

    of Forth's unique run-time environment, all in the name of some nebulous

    concept called portability.

    It is unfortunately true that Chuck Moore was right all these years:

    portability *is* a myth.  One need not look any further than C, supposedly the

    most portable of all languages judging by its popularity, for ample proof.

    Many "portable" C programs are literally riddled with #ifdef statements to

    perform conditional compilation.  You often see things like the following:

    #ifdef __X86__

    extern void DoBlort_x86( ... );

    #elsif __ARM__

    extern void DoBlort_arm(...);

    #elsif __MIPS__

    extern void DoBlort_mips( ... );

    #endif

    The above code fragment represents some of the most readable examples of how C

    achieves its platform independence.  A look through any Linux source code file

    will show much more realistic, and hairy, examples.  Getting back to the

    example, what if I don't use an 80x86, ARM, or MIPS processor?  What if I use a

    PowerPC instead?  I'm screwed -- the functionality for that function hasn't

    been defined.  So much for C's platform independence.  While C, as a language,

    is portable between platforms, the software you write in it certainly isn't.

    However, this is also true of Forth!

    A better solution would be to replace all of the above with a single

    declaration:

    extern void DoBlort(...);

    and have three independent source modules that all expose the same interface,

    one for x86, ARM, and MIPS.  Of course, it doesn't solve the platform

    independence issue, but it does certainly improve code readability and

    maintainability.  Furthermore, creation of a PowerPC-version of DoBlort no

    longer involves changing every header file or source file that references

    DoBlort in conditional compilation blocks.

    This is an example of achieving "portability through factoring," a concept that

    Moore has adhered to since the earliest days of Forth.  The equivalent to the

    above practice in Forth would be to heavily factor your software.  Stick to the

    dictum, "One word, one line," like it was a religious mandate.  It is

    unfortunate that 90% of the people who preach this *do not follow it

    themselves.*  For example, Wil Baden (IIRC), someone very well respected in the

    Forth community for his engineering prowess and knowledge of Forth, posted some

    code that performed random number generation using the Mersenne Twister.  ONE

    definition, 27 lines, using absolutely NO factorization at all.  The result was

    a definition that used gratuitous quantities of single-letter variable names

    (whose purposes are still unknown to me), and the reader is left wondering,

    "What the heck does all this do?  How do these parts interact with each other?"

     It was classic Forth write-only fare.

    I have written many small- to medium-sized tools in Forth.  Billy can attest to

    my code's high degree of readability, and indeed, even portability.  I make

    *zero* attempts to write "portable" Forth, choosing instead to use

    portability-by-factoring.  A small example would be my metronome program, which

    under PygmyForth, talks to the PC's speaker hardware directly, but under

    GForth, uses ioctls on stdout to affect the PC speaker (it will not work under

    an xterm though).  Another example would be my VIBE VI-like Block Editor.

    Here, over 40K of source code, mostly one-word-one-line, was initially written

    under GForth, making use of run-time dictionary searches using FIND and similar

    words to achieve extendability by the programmer.  In porting it to Pygmy

    Forth, which is patently not ANSI, I spent no more than an hour and a half

    writing the relavent words (which fits all on one screen, btw), and most of

    that time was spent perusing Pygmy's source to find the best way to approximate

    ANSI behavior.  The end result is no loss of functionality, and the isolation

    of words that are likely to give problems when porting it to some other

    non-ANSI environment, so porting it will be even easier then -- I know what to

    look for in advance.

    Remember that Forth, and other concatenative languages, do NOT use local

    variables; therefore, you must make interactions within a word explicit by

    explaining, using the source code itself, WHAT is trying to be done, not HOW.

    This can only be done using telegraphic names and highly factored code.  *This

    is the concatenative advantage!*  Note that this should *especially* be

    standard practice for Joy programs, because Joy, unlike Forth, can pre-parse

    the whole source before emitting code.  As a consequence, Joy compilers can

    tell whether or not a word is used only once or twice throughout the whole

    module, and thus, cleanly inline its definition where appropriate.  This

    eliminates the subroutine call overhead that is a perpetual problem in most

    Forths (and is most likely why people don't factor in Forth; however, all the

    commercial Forth vendors today produce Forths that do inline single- or

    double-use words).  However, even in Forth, I find subroutine overhead to be

    inconsequential, except in the inner-most, highly numerically intensive, loops.

     We're using 1GHz or more processors today; surely, a maximum 20 cycle penalty

    for subroutine invokations is tolerable, and that's only when the branch was

    mis-predicted.  It's substantially lower if the call was successfully

    predicted.

    While I'm rarely in total agreement with Jeff Fox, I have to concur with his

    assessment on c.l.f that ANSI Forth promulgates the "C" way of doing things in

    Forth.  While ANSI has its high points, making the return stack effectively

    off-limits as a first-class, programmer-accessible object has done much to

    limit the expressive power of Forth.  In most circumstances, people generally

    don't notice, because they're not familiar with, or even afraid of, using

    advanced control flow techniques such as backtracking.  However, use of

    backtracking and highly telegraphic word names can make *extremely*

    maintainable source code in Forth:

    : DoSomething   0 50 ForAllIntegers: OnlyEvenIntegers: Blah ;

    This technique becomes especially powerful when you desire to factor out common

    code among a number of loops.  Without this technique, you cannot create the

    equivalent of a Haskell "generator," which is instrumental in performing such a

    factorization.  As a result, code becomes harder to maintain, harder to test,

    and significantly harder to read.  I posted an example of a Mersenne Twister

    implementation in c.l.f one day, and it had three DO/LOOP constructions, ALL of

    which were nearly identical, and could have easily been factored out had ANSI

    Forth supported operations on the return stack.

    Notice how most Forth implementations simply lack the vocabulary to treat the

    dictionary as a true, first-class object as well.  You can create new words

    only by using CREATE or : (VARIABLE and CONSTANT are defined in terms of

    CREATE), both of which work by taking their input NOT from the program, but

    from the current input stream.  Also note that there is no way to iterate

    "portably" over the contents of the dictionary.  This is directly attributed to

    the lack of support for defining new control flow structures in Forth: had ANSI

    Forth supported backtracking, iterating over the dictionary *portably* would be

    a reality, even if it wasn't provided as standard equipment.

    As a result of all these mishaps, I'm forced, as an ever increasing number of

    others are, to make non-ANSI compliant Forth environments.  non-ANSI

    environments are still very popular these days, ironically, because of ANSI

    Forth itself.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## Ivan Tomac — 2003-03-15 13:21:00

    --- In concatenative@yahoogroups.com, Samuel Falvo <falvosa@y...>

    wrote:

     > > I think, though, that that is not ANS FORTH compliant; no non-

     primitive

     > > word can have a net effect on the return stack.  In particular,

     I am

     > > certain that the idiom "r> drop exit" is not ANS FORTH.

    >

    > Without giving you exceedingly uninteresting details, my feelings

     towards ANSI

     > Forth are not favorable.  ANSI Forth made a lot of decisions that

     lean towards

     > very conventional methods of programming which patently do not

     take advantage

     > of Forth's unique run-time environment, all in the name of some

     nebulous

     > concept called portability.

    >

    > It is unfortunately true that Chuck Moore was right all these

     years:

     > portability *is* a myth.  One need not look any further than C,

     supposedly the

     > most portable of all languages judging by its popularity, for

     ample proof.

    C isn't the most portable of languages by far. The reason it's so

    popular has nothing to do with it's portability - the portability is

    the result of standardization. These days most languages with well

    defined and recognized standards are at least as portable as C.

    Being a relatively low-level language, C isn't really all that

    portable by nature just like Forth. Portability in C and Forth is

    mostly enforced through standards.

    Portability does not have to be a myth though. It could be maximised

    by removing all system specific types from language (i.e. ints,

    floats, etc.) and replacing them with something more generic. Of

    course such a language would probably be fairly inefficient compared

    to C even with optimizing compilers but I wouldn't think the

    performance would be much worse then that of most other functional

    languages (which is still pretty bad though).

    I'm currently working on something like this although not for the

    sake of portability, portability just happens to be a side-effect.

    Thanks to some of the feedback, comments and discussions I've

    gathered from this board in the past mainly from Billy Tanksley,

    Manfred Von Thun and Brent Kirby I've completely redesigned my

    language from scratch (at the same time it's also starting to look a

    lot more like a typeless version of Joy instead of a functional

    version of Forth). I still have the old Forth-like version though.

     > *snip*

    >

    > A better solution would be to replace all of the above with a

     single

     > declaration:

    >

    > extern void DoBlort(...);

    >

    > and have three independent source modules that all expose the same

     interface,

     > one for x86, ARM, and MIPS.  Of course, it doesn't solve the

     platform

     > independence issue, but it does certainly improve code readability

     and

     > maintainability.  Furthermore, creation of a PowerPC-version of

     DoBlort no

     > longer involves changing every header file or source file that

     references

     > DoBlort in conditional compilation blocks.

    >

     Not really a better solution - that's what #ifdefs mostly do: you

    end up with a bunch of different versions of DoBlort() for different

    processors. It does improve readability a bit though.

    Depending on the code and how well it's written you might not have

    to change all that many header files either. However trying to

    understand what those header files do might be a bit tough with all

    those conditional defines.

     > This is an example of achieving "portability through factoring," a

     concept that

     > Moore has adhered to since the earliest days of Forth.  The

     equivalent to the

     > above practice in Forth would be to heavily factor your software.

     Stick to the

    IIRC Chuck Moore advocates rewriting a program for every new system

    instead of porting an existing program.

     > *snip*

    >

    > Notice how most Forth implementations simply lack the vocabulary

     to treat the

     > dictionary as a true, first-class object as well.  You can create

     new words

     > only by using CREATE or : (VARIABLE and CONSTANT are defined in

     terms of

     > CREATE), both of which work by taking their input NOT from the

     program, but

     > from the current input stream.  Also note that there is no way to

     iterate

    Dictionary in Forth cannot be a first class object. If you made it a

    first class object you'd end up with a new language. In Forth there

    are no first class objects and nothing is off-limits and like you

    said that's what ANS Forth is trying to change - to force

    programmers to treat certain things as special such as the return

    stack.

    The way I see CREATE and : and other defining words is as a part of

    a separate language. That separate language also includes all

    immediate and compiling words.

    Chuck Moore went as far as to eliminate defining words and replace

    them with colors in ColorForth to further separate defining words

    from normal words.

    Ivan

## Samuel Falvo — 2003-03-15 21:13:50

    > C isn't the most portable of languages by far. The reason it's so

     I used C because it's considered to be a "portable" language by academia and

    industry alike.

     > popular has nothing to do with it's portability - the portability is

     Historical evidence seems to suggest otherwise.  As I currently understand the

    history of C and Unix, the reason it's so popular is precisely because the

    compiler was touted, very early on, as being portable by AT&T.  "Look, we can

    implement Unix on both the PDP-7 AND the PDP-11!"  It spread throughout the

    academic community like wildfire, and a whole generation of programmers grew up

    on it.  Another claim to fame for C was its low-level interface to systems

    hardware (e.g., explicit pointer operations, etc).  Once Unix was ported to the

    VAX architecture, C's fate as a foundation language was sealed.  This is the

    reason it's popular today.

     > the result of standardization. These days most languages with well

     The popularity of C was readily apparent long before ANSI or ISO got involved.

     > defined and recognized standards are at least as portable as C.

    > Being a relatively low-level language, C isn't really all that

    > portable by nature just like Forth. Portability in C and Forth is

    > mostly enforced through standards.

     I disagree.

    Portability in C is through the specification of the language itself, a mapping

    between syntactical elements and their run-time behavior, in addition to the

    supporting, standardized run-time libraries.  Many people don't realize that

    the standard C libraries are actually a proper subset of Unix, 3rd edition.

    Even today, the standard run-time environment for C is implemented, if not in

    the Unix kernel itself, then at least in the library that interfaces user-land

    processes to the kernel: libc.  This, BTW, further cements the tight coupling a

    language has with its operating system, a trait many people insist that C

    lacks.

    Portability in Forth is derived through other means, especially since Forth has

    no common syntax, except for the colon definition (and ColorForth even does

    away with that).  However, unlike C, it does have something much more powerful:

    a common model of the run-time *environment*, whether virtualized or physically

    implemented.  By blurring the distinction between basic primitive and user-made

    construction, portability can be achieved through merely (re)defining basic

    primitives.  It fulfills Backus' desired requirement that larger programs be

    composed from smaller programs, and not through a sequence of statements each

    of which is partially responsible for partial state changes.  Though Forth

    isn't a functional language (at least, not in a pure sense), it meets a *LOT*

    of FP's requirements.

     > Portability does not have to be a myth though. It could be maximised

    > by removing all system specific types from language (i.e. ints,

    > floats, etc.) and replacing them with something more generic. Of

     This is precisely what factoring your code provides, hence

    portability-through-factoring still applies.

     > course such a language would probably be fairly inefficient compared

    > to C even with optimizing compilers but I wouldn't think the

    > performance would be much worse then that of most other functional

    > languages (which is still pretty bad though).

     Too many people are obscessed(sp?) with speed.  Just write the damn program,

    and get it working.  Worry about speed later; that's why profilers exist.  :-)

    Lisp is a horrifically slow system in most implementations; but yet, it's fast

    enough to power virtually ALL of Yahoo!'s web serving needs, including e-mail,

    it's shopping mall, and its online gaming community.  Python is often times

    slower than Lisp, and demonstrably slower than Perl, but yet it powers one of

    the world's most sophisticated and growing web applications environment: Zope.

    In martial arts, there's a cliche that evolved, because it's provably true:

    Speed Is An Illusion.

    The more I read the literature, the more I'm absolutely convinced that the

    sorry state of software today ultimately derives from the programmer's total

    lack of understanding of how computers *really* work under the hood, and

    therefore, what does or does not influence performance the greatest.  In their

    quest to make everything as fast as possible, they've created computer designs

    with more transistors in one chip than the whole population of a large city

    (sometimes even a small country), software as inlined and unrolled as possible,

    attempting to minimize branches.  But what they fail to grasp is that, in order

    to feed those transistors data, you need caches, and to feed those caches, you

    need still more caches, ultimately terminating in our relatively slow DRAMs

    today.  And ultimately, all that unrolled code has to be transferred over the

    "von Neumann Bottleneck" (as Backus calls it, and which I agree).

    Factoring your code optimizes for size, for sure, but it doesn't necessarily

    have to come at the cost of speed.  I've found that smaller code can sometimes

    run as fast, if not faster than, larger code!  The only explanation I can think

    of is that everything sits inside the CPU's inner-most caches.  Subroutine call

    overheads act to slow things down, but when thrashing the caches, the

    advantages of unrolling and inlining become equally moot (especially when the

    bus is in regular contention with I/O device activity).

    There was interesting research performed by Anton Ertl that, for certain

    classes of processors, a direct-threaded Forth implementation actually ran

    *faster* than an equivalent, traditionally-written assembly language program.

    The reason was that, despite having higher clock counts because of the extra

    interpretation level, the lack of cache thrashing more than made up for the

    difference.

    Obviously, the decision of when to unroll and when to call is going to be not

    only processor dependent, but bus/motherboard dependent as well (this includes,

    by extension, what peripherals are attached to the bus).  The number of

    variables involved with making a sound decision is simply too much for people

    to grasp up front, and is utterly impossible for a compiler to predict.  Hence,

    you should always design your code as tightly and as well factored as possible,

    if for nothing else than the *speculation* that the small size *can* give it

    reasonable performance (it runs entirely from cache).  Use unconditional

    branches as much as possible, so as to minimize the chances of being

    mispredicted.  Then, if you *really* need the speed, you can hand-optimize

    where necessary, using profilers to locate the spots that needs it most.  This

    forms an interactive feedback loop, resulting in an iterative, step-wise

    refinement of your program to suit a particular set of requirements.

    But this brings up another good point: if you minimize the subroutine overhead

    to as little as possible (ideally being 0 clocks, but 2 clocks being more

    realistic), suddenly, well-factored software becomes highly desirable.  Smaller

    code footprint takes less time to transfer over the bus, takes less cache

    space, and would execute with effectively zero overhead.  This suggests that

    complex, transistor-intensive systems that attempt to minimize the amount of

    branching is the WRONG WAY TO GO for processor designs.  The 680x0 and x86, and

    a whole slew of RISC architectures, seem to promulgate this design philosophy,

    much to the detriment of the state of the art.

    Consider that a 4MHz 6502 (an 8-bit, highly memory bound processor, with an

    8-bit memory path) was able to out-perform an 5MHz 8086 (a 16-bit,

    register-to-register processor, with a 16-bit memory path) universally across a

    number of benchmarks put at it.  There are two reasons for this: one, I've

    already covered -- memory latency will severely decrease performance.  The

    other, however, is that the 6502's subroutine overhead is only 12 cycles (6 for

    a call, 6 for a return), versus the 8086's total of 39!!

    Subroutine call overheads for modern processors have only gotten worse.  While

    the Pentium can resolve and execute a subroutine call much faster than the 39

    cycles of yesteryear, there are other factors that need to be considered, such

    as the time taken reloading a cache-line, mis-predicted branches that flush not

    only the instruction queue, but also the pipeline, etc.

    Note that stack architectures need not be the only architectures that are

    optimized for branching, though they certainly do require the least amount of

    transistors.  The only reason the 6502 takes 6 cycles to call or return from a

    subroutine is because it only has one ALU and one datapath leading to it

    internally.  With multiple datapaths, it could be reduced to 3 cycles --

    closely approximating the performance of an ideal stack processor.  With a

    wider bus to memory, and instruction pre-fetching, it can be reduced to 1.

    With caching the stack using a special purpose cache, it can be reduced to 0.5.

     All this IS possible on a register or accumulator architecture.  Just because

    Intel hasn't done it, doesn't mean it can't possibly be done.

    Speaking of stack processors, interestingly enough, the LACK of

    superscalability of stack architectures would seem to make them highly

    desirable for implementation of graph reduction machines.  Single-cycle

    instruction execution performance, combined with conditional skips (instead of

    conditional branches) or predication in a stack architecture would require so

    few transistors (on the order of 2000 to 4000 gates at best) that you can

    literally pack *HUNDREDS* of these processors on a single processor die using

    modern fabrication techniques, and still have enough room for a multi-ported,

    512KB level-1 cache.  Chuck Moore's 25X architecture, though not fabricated yet

    (and may never be, unfortunately), has been successfully simulated with rather

    intriguing results (it is the only architecture I'm aware of that can emulate

    most FPGA functions in software).  Functional programming entheusiasts would go

    bonkers over such an architecture, since it's basically ready made for

    applicative functional programming languages.

     > Not really a better solution - that's what #ifdefs mostly do: you

    > end up with a bunch of different versions of DoBlort() for different

    > processors. It does improve readability a bit though.

     Without drawing on the literature that is commonly available in computer

    science and engineering circles, I must sorely and vehemently disagree with

    your assertion that preprocessor macros make for higher readability source,

    based solely on my experience maintaining legacy code for many years.

    The widespread success of (even systems) programming languages that do not have

    preprocessor macros stands as strong evidence of their redundancy.  Why should

    I ever have to read something like #ifdef when I just want to know what

    functionality a module needs?  Configuration management should not exist inside

    the program source -- it should exist, at best, in its Makefile (that's what

    it's there for, after all).

     > IIRC Chuck Moore advocates rewriting a program for every new system

    > instead of porting an existing program.

     Chuck Moore, when working for Forth, Inc., would port a complete Forth

    environment over to a whole new processor architecture in a matter of hours to

    days.  He achieved this speed by writing a new assembler for the target

    architecture (pretty much an absolute necessity, no matter how you look at it),

    and then wrote a new low-level set of words which the higher-level words relied

    upon.  This set of low-level words is known and well-bounded.  This was

    portability-by-factoring at its finest.

    Even today, his ColorForth environment is architected this way, having its

    foundations on MachineForth.  MachineForth is a set of 29 primitives,

    implemented as macros/immediate words.  EVERYTHING else in the Forth derives

    from these primitives, and are written in Forth itself.

    He rewrote his OKAD software because the previous architecture didn't out well

    for his future design work.  Moore admits that the original OK and OKAD systems

    were failed experiments.  It was too tightly integrated, didn't allow for

    programmability, etc.  Adding these kinds of things can definitely cause global

    changes in software, regardless of how well factored it is.  When the basic,

    underlying metaphor of a project changes, you almost always have to start over

    from scratch.  This is as true in C as it is in Forth.  (e.g., changing the

    user interface metaphor from VI to Raskin's THE in my block editor would force

    me to do a grass-roots redesign of the application.)

    OKAD-II has been ported between the F21 and Pentium systems.  It's remained

    largely the same code base.

    Chuck doesn't advocate blind re-writes of whole applications.  If you read his

    material, he advocates instead that you consider the *possibility* of a

    rewrite.  The distinction is an important one.

     > Dictionary in Forth cannot be a first class object. If you made it a

    > first class object you'd end up with a new language. In Forth there

    > are no first class objects and nothing is off-limits and like you

     This is a contradiction: if nothing is off-limits, how can the data-stack not

    be a first-class object?  Return stack?  Dictionary?

    You say that the dictionary "cannot" be a first-class object in Forth, as if

    you invented the language yourself.  Prove to me why it can't be a first-class

    object in Forth.

     > The way I see CREATE and : and other defining words is as a part of

    > a separate language. That separate language also includes all

    > immediate and compiling words.

    > Chuck Moore went as far as to eliminate defining words and replace

    > them with colors in ColorForth to further separate defining words

    > from normal words.

     Instead of defining words, he has defining colors.  The basic, underlying

    mechanisms are still *exactly* the same: when the interpretter sees a red word,

    it creates a word header.  When it sees a green word, it compiles a subroutine

    call.  When it sees a green number, it compiles a load instruction.  All he's

    managed to do is remove the modality of Forth.  Otherwise, it is no different

    from normal Forth, including its lack of ability to dynamically create words at

    run-time.

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## John Cowan — 2003-03-15 23:15:19

    Samuel Falvo scripsit:

     > Lisp is a horrifically slow system in most implementations;

     This is absolutely false, a meme that needs to be stomped out wherever

    it appears.  As long ago as 1973, the Lisp compiler on the DEC PDP-10

    was outspeeding the vendor's Fortran compiler.  Modern Lisp compilers

    do at least as well.

     > In martial arts, there's a cliche that evolved, because it's provably true:

    > Speed Is An Illusion.

     "A Lisp programmer is one who knows the value of everything, but the cost

    of nothing."

    	--Alan J. Perlis (http://www.cs.yale.edu/homes/perlis-alan/quotes.html)

    --

    John Cowan           http://www.ccil.org/~cowan              cowan@...

    To say that Bilbo's breath was taken away is no description at all.  There

    are no words left to express his staggerment, since Men changed the language

    that they learned of elves in the days when all the world was wonderful.

            --_The Hobbit_

## Ivan Tomac — 2003-03-16 03:49:28

    --- In concatenative@yahoogroups.com, Samuel Falvo <falvosa@y...>

    wrote:

     > > C isn't the most portable of languages by far. The reason it's

     so

     >

    > I used C because it's considered to be a "portable" language by

     academia and

     > industry alike.

    >

    > > popular has nothing to do with it's portability - the

     portability is

     >

    > Historical evidence seems to suggest otherwise.  As I currently

     understand the

     > history of C and Unix, the reason it's so popular is precisely

     because the

     > compiler was touted, very early on, as being portable by

     AT&T.  "Look, we can

     > implement Unix on both the PDP-7 AND the PDP-11!"  It spread

     throughout the

     > academic community like wildfire, and a whole generation of

     programmers grew up

     > on it.  Another claim to fame for C was its low-level interface to

     systems

     > hardware (e.g., explicit pointer operations, etc).  Once Unix was

     ported to the

     > VAX architecture, C's fate as a foundation language was sealed.

     This is the

     > reason it's popular today.

    >

     AT&T did publicize C a fair bit. At the time C offered a unique mix

    of speed while it

    was still reasonably high-level compared to alternatives and was

    also easier to grasp

    for those who already knew a language such as Pascal.

    Another thing that I think had a big effect on C's popularity (and

    this is just my

    opinion) is that it was made in a big company rather than in a

    garage or a uni.

    Many people back then and even now think that if something is made

    in a company it has

    to be better than something made in a garage or a uni.

     > > the result of standardization. These days most languages with

     well

     >

    > The popularity of C was readily apparent long before ANSI or ISO

     got involved.

     >

    > > defined and recognized standards are at least as portable as C.

    > > Being a relatively low-level language, C isn't really all that

    > > portable by nature just like Forth. Portability in C and Forth

     is

     > > mostly enforced through standards.

    >

    > I disagree.

    >

    > Portability in C is through the specification of the language

     itself, a mapping

     > between syntactical elements and their run-time behavior, in

     addition to the

     > supporting, standardized run-time libraries.  Many people don't

     realize that

    C is not portable by nature. Any language that allows you to mess

    around with pointers,

    that defines ints and floats and other types in a certain way, that

    allows you to mess

    around with alignment of data on purpose is not portable by nature.

    It's a fact that you can write a portable program in C if you try

    really hard but it's

    also a fact that you can easily write a piece of code in C that

    won't be portable at all.

    In a way this is similar to how you can write object oriented

    programs in plain C even

    though C is not an object oriented language by nature.

     > the standard C libraries are actually a proper subset of Unix, 3rd

     edition.

     > Even today, the standard run-time environment for C is

     implemented, if not in

     > the Unix kernel itself, then at least in the library that

     interfaces user-land

     > processes to the kernel: libc.  This, BTW, further cements the

     tight coupling a

     > language has with its operating system, a trait many people insist

     that C

     > lacks.

    >

    > Portability in Forth is derived through other means, especially

     since Forth has

     > no common syntax, except for the colon definition (and ColorForth

     even does

    ANS-Forth is about as portable as C. Of course writing portable

    programs in Forth prevents

    you from using the things that make Forth great IMO (and from your

    comments I think you

    agree with that statement).

     > *snip*

    >

    > > Portability does not have to be a myth though. It could be

     maximised

     > > by removing all system specific types from language (i.e. ints,

    > > floats, etc.) and replacing them with something more generic. Of

    >

    > This is precisely what factoring your code provides, hence

    > portability-through-factoring still applies.

    >

     No, this is different. For example a programming language that

    doesn't have 32-bit

    ints and floats but instead just has bignums eliminates a whole

    bunch of portability

    problems that factoring cannot.

     > > course such a language would probably be fairly inefficient

     compared

     > > to C even with optimizing compilers but I wouldn't think the

    > > performance would be much worse then that of most other

     functional

     > > languages (which is still pretty bad though).

    >

    > Too many people are obscessed(sp?) with speed.  Just write the

     damn program,

     > and get it working.  Worry about speed later; that's why profilers

     exist.  :-)

     > Lisp is a horrifically slow system in most implementations; but

     yet, it's fast

     > enough to power virtually ALL of Yahoo!'s web serving needs,

     including e-mail,

     > it's shopping mall, and its online gaming community.  Python is

     often times

     > slower than Lisp, and demonstrably slower than Perl, but yet it

     powers one of

     > the world's most sophisticated and growing web applications

     environment: Zope.

     >

     It depends on the application. There are too many applications out

    there for

    which functional languages would simply be too slow considering the

    current

    state of compilers.

     > *snip*

    >

    > > Not really a better solution - that's what #ifdefs mostly do:

     you

     > > end up with a bunch of different versions of DoBlort() for

     different

     > > processors. It does improve readability a bit though.

    >

    > Without drawing on the literature that is commonly available in

     computer

     > science and engineering circles, I must sorely and vehemently

     disagree with

     > your assertion that preprocessor macros make for higher

     readability source,

     > based solely on my experience maintaining legacy code for many

     years.

     >

     I think you misunderstood what I said. Actually I should have

    phrased this a bit

    better. I was agreeing with you that splitting things up into

    modules is more

    readable than conditional defines. But as far as portability goes

    it's pretty

    much the same, you're not making the code more portable, you're only

    making it

    more readable.

     > The widespread success of (even systems) programming languages

     that do not have

     > preprocessor macros stands as strong evidence of their

     redundancy.  Why should

     > I ever have to read something like #ifdef when I just want to know

     what

     > functionality a module needs?  Configuration management should not

     exist inside

     > the program source -- it should exist, at best, in its Makefile

     (that's what

     > it's there for, after all).

    >

     Conditional defines and preprocessors aren't bad. They often

    complement the

    language. They can often improve readability of the code and

    decrease redundancy

    in the code if they're used carefully. Defining and immediate words

    in Forth

    act in a way that resembles preprocessor macros.

     > *snip*

    > Chuck doesn't advocate blind re-writes of whole applications. If

     you read his

     > material, he advocates instead that you consider the *possibility*

     of a

     > rewrite. The distinction is an important one.

     I stand corrected.

     >

    > > Dictionary in Forth cannot be a first class object. If you made

     it a

     > > first class object you'd end up with a new language. In Forth

     there

     > > are no first class objects and nothing is off-limits and like

     you

     >

    > This is a contradiction: if nothing is off-limits, how can the

     data-stack not

     > be a first-class object?  Return stack?  Dictionary?

    >

    > You say that the dictionary "cannot" be a first-class object in

     Forth, as if

     > you invented the language yourself.  Prove to me why it can't be a

     first-class

     > object in Forth.

    >

     Not a contradiction. The preferred way of programming in Forth is

    modifying the

    language itself to suit the task at hand. By doing that you yourself

    are

    changing Forth. This is something ANS-Forth is against.

    The fact that defining words take their input from the input stream

    and not the

    program itself further reinforces the comparison with preprocessor

    macros.

    If you made the dictionary a first class object in Forth you'd end

    up with a new

    language - it wouldn't be Forth anymore. Forth allows you to do this

    and if you

    really need to do this for the task at hand even encourages you to

    do this but

    the end result is not Forth.

     > > The way I see CREATE and : and other defining words is as a part

     of

     > > a separate language. That separate language also includes all

    > > immediate and compiling words.

    > > Chuck Moore went as far as to eliminate defining words and

     replace

     > > them with colors in ColorForth to further separate defining

     words

     > > from normal words.

    >

    > Instead of defining words, he has defining colors.  The basic,

     underlying

     > mechanisms are still *exactly* the same: when the interpretter

     sees a red word,

     > it creates a word header.  When it sees a green word, it compiles

     a subroutine

     > call.  When it sees a green number, it compiles a load

     instruction.  All he's

     > managed to do is remove the modality of Forth.  Otherwise, it is

     no different

     > from normal Forth, including its lack of ability to dynamically

     create words at

     > run-time.

    >

     Yes, defining colors. The mechanisms are the same. But it's because

    they're special

    and not like normal words. It's because they belong to a separate

    language that

    coexists in symbiosis with Forth itself.

    Ivan

## Ivan Tomac — 2003-03-16 03:52:13

    I apologise about the formatting, I'm having some problems with my

    web browser.

    Ivan

## Samuel Falvo — 2003-03-16 19:56:49

    > Many people back then and even now think that if something is made

    > in a company it has

    > to be better than something made in a garage or a uni.

     Java.

     > If you made the dictionary a first class object in Forth you'd end

    > up with a new

    > language - it wouldn't be Forth anymore. Forth allows you to do this

    > and if you

    > really need to do this for the task at hand even encourages you to

    > do this but

    > the end result is not Forth.

     I disagree with this.  If this were true, then as soon as I write my first

    :-definition, the language I'm programming in is no longer Forth.  By

    extension, absolutely no existing ANSI Forth implementations are Forth, since

    they all define words (usable by applications even) above and beyond the ANSI

    standard.

    If CREATE and : were defined in terms of a more orthogonal interface to the

    dictionary, then it'd still be Forth.  Just because I expose the words that

    create a new word header given any arbitrary string on the stack (and such

    words do exist in all Forths; though, unfortunately, 99% of them are

    headerless!) doesn't cause it to not be Forth anymore.  This is like saying

    Visual C++ and Borland C++ aren't C++ anymore, because they expose the Windows

    API to the programmer.

     > Yes, defining colors. The mechanisms are the same. But it's because

    > they're special

    > and not like normal words. It's because they belong to a separate

    > language that

    > coexists in symbiosis with Forth itself.

     I apologize, but I just can't agree with this.  The issue with the colors is

    one of modality, not language structure, because colors do not exist as

    separate tokens, but rather as an attribute of each word found in the source.

    (Though, it's intriguing to note that, as modeless as ColorForth is, it's still

    modal.  : VARIABLE and other such words set the behavior upon seeing a red

    word, and the programmer must be aware of this at all times.  But I digress.)

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Web Hosting - establish your business online

    http://webhosting.yahoo.com

## phimvt@lurac.latrobe.edu.au — 2003-03-17 06:35:42

    On Fri, 14 Mar 2003, John Cowan wrote:

     > phimvt@... scripsit:

    >

    > > Indeed, the use of local procedures as parameters in recursive

    > > calls appears to be a sort of black art, and I seem to be one

    > > of its few practitioners.

    >

    > In Pascal, I suppose you mean.

     Yes, I did. I should have made that clearer.

     >                                Of course the entire Lisp (and especially

    > Scheme) community practices this art with abandon, and doesn't consider

    > it black.

     Do you happen to know of a reference? It might be good for snarfing

    for Joy.

     >           In Scheme, furthermore, you can return a local procedure as

    > the value of one of its enclosing procedures.

     I think this will also be true of ML and Haskell - all those languages

    in which functions are "first class citizens" (and live on the heap).

    I have practised the art in Joy in the two backtracking libraries.

     >

    > The GNU dialect of C allows local procedures and procedure arguments,

     Do you happen to know whether it really passes on (as a static link or

    as a display) the current local environment? Without doing that it

    would not allow the black art. [I seem to remember reading somewhere

    that a language which does not rely on a heap has to decide between

    1) passing on the current local environment, or 2) allowing assignments

    (of global procedures only) to procedural variables. But I cannot

    remember where I saw this. It made sense at the time.]

     > but ANSI C does not.

      - Manfred

## John Cowan — 2003-03-17 12:44:32

    phimvt@... scripsit:

     > Do you happen to know of a reference? It might be good for snarfing

    > for Joy.

     Not offhand.  I think the Scheme community considers the technique obvious,

    and as such it is only documented as folklore.

     > I think this will also be true of ML and Haskell - all those languages

    > in which functions are "first class citizens" (and live on the heap).

    > I have practised the art in Joy in the two backtracking libraries.

     Unless I am very mistaken, this is *not* true of Standard ML, which does

    not implement full continuations.

     > > The GNU dialect of C allows local procedures and procedure arguments,

    >

    > Do you happen to know whether it really passes on (as a static link or

    > as a display) the current local environment?

     It really does.  In order to make it transparent to the caller whether

    it is invoking an ordinary (global) procedure or a nested one, the

    function pointer for a nested procedure points to a short stretch of

    code called a "trampoline", which sets up the callee's environment correctly

    and then jumps to it.  "The trampoline you can understand is not the

    true trampoline."  See

    http://people.debian.org/~aaronl/Usenix88-lexic.pdf

    Attempting to invoke a nested procedure whose containing procedure has

    exited causes undefined behavior, of course.

    See http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Nested-Functions.html#Nested%20Functions

    Now that gcc is so pervasive, its extensions to C (most of which were

    introduced in order to debug features put into the back end to implement

    Pascal, Algol 60, and other languages) are well worth considering, notably

    the labels-as-values that makes true assigned GOTO possible -- great for

    implementing bytecode interpreters!

    An index to the features is at

    http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/C-Extensions.html#C%20Extensions

    --

    John Cowan           http://www.ccil.org/~cowan              cowan@...

    To say that Bilbo's breath was taken away is no description at all.  There

    are no words left to express his staggerment, since Men changed the language

    that they learned of elves in the days when all the world was wonderful.

            --_The Hobbit_

## phimvt@lurac.latrobe.edu.au — 2003-03-18 07:06:58

    On Mon, 17 Mar 2003, John Cowan wrote:

     > phimvt@... scripsit:

     [.. a propos implementing backtracking by means of continuations ..]

     > > Do you happen to know of a reference? It might be good for snarfing

    > > for Joy.

    >

    > Not offhand.  I think the Scheme community considers the technique obvious,

    > and as such it is only documented as folklore.

     I can only find the well-known call-cc technique (+ the amb function).

    But I meant something different: using recursive calls with a local

    procedure as a parameter to the recursive call. See the example at the

    end.

     > > I think this will also be true of ML and Haskell - all those languages

    > > in which functions are "first class citizens" (and live on the heap).

    > > I have practised the art in Joy in the two backtracking libraries.

    >

    > Unless I am very mistaken, this is *not* true of Standard ML, which does

    > not implement full continuations.

     Since "the art" does not involve any special features such as call-cc,

    something like the example at the end should also work in Scheme, Common

    Lisp, ML and Haskell - I think.

     > > > The GNU dialect of C allows local procedures and procedure arguments,

    > >

    > > Do you happen to know whether it really passes on (as a static link or

    > > as a display) the current local environment?

    >

    > It really does.  In order to make it transparent to the caller whether

    > it is invoking an ordinary (global) procedure or a nested one, the

    > function pointer for a nested procedure points to a short stretch of

    > code called a "trampoline", which sets up the callee's environment correctly

    > and then jumps to it.  "The trampoline you can understand is not the

    > true trampoline."  See

    > http://people.debian.org/~aaronl/Usenix88-lexic.pdf

     Thank you for this, it was an eye-opener for me. This seems to be a way

    of passing on the static link in languages in which such a link is

    not normally passed on in procedure calls. Very clever. And incidentally,

    perhaps the best way of understanding static links even when local

    procedures can *not* be used as parameters is in Wirth's original book,

    Algorithms + Data Structes = Programs, last Chapter (which unfortunately

    got omitted in later editions).

     > See http://gcc.gnu.org/onlinedocs/gcc-3.2.2/gcc/Nested-Functions.html#Nested%20Functions

    > Now that gcc is so pervasive, its extensions to C (most of which were

    > introduced in order to debug features put into the back end to implement

    > Pascal, Algol 60, and other languages) are well worth considering, notably

    > the labels-as-values that makes true assigned GOTO possible -- great for

    > implementing bytecode interpreters!

     I have often wondered whether Joy could be implemented in a way

    which is very different from the current one. Anyone having thoughts

    on this?

    I include one program which uses a local procedure as a parameter

    in a recursive call to the enclosing procedure. Note that there

    is only one local variable n : integer.

                                                        The program reads

       lines of numbers, and for each line that it has read it will write one

       line, containing the even numbers in their original order, then a

       space of four characters, then the odd numbers in their original

       order.

    PROGRAM oddevn(input,output);

    PROCEDURE space;

    BEGIN write('    ') END;

    PROCEDURE odev(PROCEDURE cp);

    VAR n : integer;

        PROCEDURE writelater;

        BEGIN cp; write(n:0,' ') END;

    BEGIN (* odev *)

    IF eoln THEN cp ELSE

        BEGIN

        read(n);

        IF n MOD 2 = 0

            THEN BEGIN write(n:0,' '); odev(cp) END

            ELSE odev(writelater)         (* recursive call with local proc *)

        END

    END; (* odev *)

    BEGIN (* main, oddevn *)

    WHILE NOT eof  DO

        BEGIN odev(space); readln; writeln END

    END. (* main, oddevn *)

    Of course this is a silly program, used to illustrate second order

    recursion, from Chapter 8 of my Pascal page.

          http://www.latrobe.edu.au/philosophy/phimvt/s00bok.html

    The technique is used seriously in Chapters 9 10 11 15 16 20 to

    implementing backtracking. There is also some third order recursion,

    and, if you can stomach this sort of thing, fourth order recursion

    (in the Appendix, part 4).

    It would be of interest to me to know whether gcc can handle

    this sort of thing (as I mentioned before, the version of p2c

    that I once tried failed.) Also, I am confident (without positive

    proof) that this sort of thing works equally well in Scheme, Lisp,

    ML, Haskell (and, if I understand it correctly, perhaps in

    stackless python). Does anybody want to try ?

    Thanks for the comments, John.

      - Manfred

## Samuel Falvo — 2003-03-18 20:03:01

    > PROGRAM oddevn(input,output);

    >

    > PROCEDURE space;

    > BEGIN write('    ') END;

    >

    > PROCEDURE odev(PROCEDURE cp);

    > VAR n : integer;

    >

    >     PROCEDURE writelater;

    >     BEGIN cp; write(n:0,' ') END;

    >

    > BEGIN (* odev *)

    > IF eoln THEN cp ELSE

    >     BEGIN

    >     read(n);

    >     IF n MOD 2 = 0

    >         THEN BEGIN write(n:0,' '); odev(cp) END

    >         ELSE odev(writelater)         (* recursive call with local proc *)

    >     END

    > END; (* odev *)

    >

    > BEGIN (* main, oddevn *)

    > WHILE NOT eof  DO

    >     BEGIN odev(space); readln; writeln END

    > END. (* main, oddevn *)

     Thanks for posting this example.  I'll try re-coding it in Oberon, to see if

    Oberon behaves as expected.  I'll be using the oo2c compiler.  Perhaps Steve

    can use the Linux Native Oberon environment to see if his compiler works

    similarly?

    I know this is wildly off-topic for the list, but I think this is a worthwhile

    investigation, as studying how these languages support the feature can provide

    valuable clues/insights on how to do similar things with concatenative

    languages.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!

    http://platinum.yahoo.com

## Samuel Falvo — 2003-03-18 20:59:13

    OK, here's the Oberon program I've written:

    MODULE OddEven;

      IMPORT In, Out;

      TYPE

        Callback = PROCEDURE();

      VAR

        ignoredLine: ARRAY 128 OF CHAR;

      PROCEDURE space();

        BEGIN

          Out.String( "    " )

        END space;

      PROCEDURE odev( cb: Callback );

        VAR

          n: INTEGER;

        PROCEDURE Print( n: INTEGER );

          BEGIN

            Out.Int( n, 0 );

            Out.String( " " );

          END Print;

        PROCEDURE WriteLater();

          BEGIN

            cb();

            Print( n );

          END WriteLater;

        BEGIN

          In.Int(n);

          IF (n MOD 2) = 0 THEN

            Print( n );

            odev( cb )

          ELSE

            odev( WriteLater )

          END

        END odev;

    BEGIN

      WHILE ~In.Done() DO

        odev( space );

        In.Line( ignoredLine );

        Out.Ln()

      END

    END OddEven.

    While the syntax of the compiler fully supports the notation of recursively

    invoking inner functions, and passing them around as procedure pointers, the

    oo2c compiler does not permit this.  However, if oo2c were to implement

    trampolines like GCC does for references to inner procedures, then there's no

    reason why Oberon shouldn't support the feature.  However, issues of

    type-safety come into play when doing this, which is presumably why Oberon

    doesn't permit this construction.

    Shucks.  Oh well...

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!

    http://platinum.yahoo.com

## Ivan Tomac — 2003-03-18 22:37:09

    --- In concatenative@yahoogroups.com, Samuel Falvo <falvosa@y...>

    wrote:

     > > If you made the dictionary a first class object in Forth you'd

     end

     > > up with a new

    > > language - it wouldn't be Forth anymore. Forth allows you to do

     this

     > > and if you

    > > really need to do this for the task at hand even encourages you

     to

     > > do this but

    > > the end result is not Forth.

    >

    > I disagree with this.  If this were true, then as soon as I write

     my first

     > :-definition, the language I'm programming in is no longer Forth.

     By

     > extension, absolutely no existing ANSI Forth implementations are

     Forth, since

     > they all define words (usable by applications even) above and

     beyond the ANSI

     > standard.

    >

    > If CREATE and : were defined in terms of a more orthogonal

     interface to the

     > dictionary, then it'd still be Forth.  Just because I expose the

     words that

     > create a new word header given any arbitrary string on the stack

     (and such

     > words do exist in all Forths; though, unfortunately, 99% of them

     are

     > headerless!) doesn't cause it to not be Forth anymore.  This is

     like saying

     > Visual C++ and Borland C++ aren't C++ anymore, because they expose

     the Windows

     > API to the programmer.

    >

     That has nothing to do with this. Defining new words in Forth is just

    like writing a library of functions in C. Neither breaks the

    language.

    If however a newly defined word replaces, breaks or modifies the

    behaviour of existing words as defined by a standard then you do end

    up with a new language or at least a new dialect - even more so

    since Forth itself doesn't have any reserved words and allows you to

    modify and change anything you want. Making Forth dictionary a first

    class object would change the behaviour of many Forth words and

    hence change Forth itself unless you created a new set of words to

    manipulate that dictionary and unless that dictionary was separated

    from the standard dictionary.

     > > Yes, defining colors. The mechanisms are the same. But it's

     because

     > > they're special

    > > and not like normal words. It's because they belong to a

     separate

     > > language that

    > > coexists in symbiosis with Forth itself.

    >

    > I apologize, but I just can't agree with this.  The issue with the

     colors is

     > one of modality, not language structure, because colors do not

     exist as

     > separate tokens, but rather as an attribute of each word found in

     the source.

     > (Though, it's intriguing to note that, as modeless as ColorForth

     is, it's still

     > modal.  : VARIABLE and other such words set the behavior upon

     seeing a red

     > word, and the programmer must be aware of this at all times.  But

     I digress.)

     >

     I don't think you understood what I was trying to say.

    Forth itself is typeless, has no reserved words and gives the

    programer amazing amount of freedom. The reason why he replaced the

    defining words with colors is so that he could conceptually make

    them stand out from normal words. Again I should point out the

    similarities between defining and immediate words and preprocessor

    macros.

    Ivan

## Samuel Falvo — 2003-03-18 23:29:17

    > That has nothing to do with this. Defining new words in Forth is just

    > like writing a library of functions in C. Neither breaks the

    > language.

     It has everything to do with it; you suggested that my proposal to add words

    which expose the dictionary in a more run-time accessible way would change the

    language significantly to no longer be considered Forth.  This is, of course,

    false, as CREATE and : are themselves already built up upon such functionality.

     My concern is that such functionality isn't made public (much less portable)

    to the programmer, which severely hinders certain types of metaprogramming

    under Forth.

     > If however a newly defined word replaces, breaks or modifies the

    > behaviour of existing words as defined by a standard then you do end

    > up with a new language or at least a new dialect - even more so

    > since Forth itself doesn't have any reserved words and allows you to

    > modify and change anything you want. Making Forth dictionary a first

    > class object would change the behaviour of many Forth words and

    > hence change Forth itself unless you created a new set of words to

    > manipulate that dictionary and unless that dictionary was separated

    > from the standard dictionary.

     I asked you once before for a proof of this, and I'm going to ask you again.

    Until I see a definite proof, I cannot and will not accept this assertion.

     > them stand out from normal words. Again I should point out the

    > similarities between defining and immediate words and preprocessor

    > macros.

     You say this as if it were somehow ignored by me.  As the author of several

    Forth implementations, and one more coming shortly, I can assure you that I

    know full well the differences and similarities between preprocessor macros and

    immediate words.  However, it is not at all relavent to the issue.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!

    http://platinum.yahoo.com

## Steven Shaw — 2003-03-19 06:03:58

    > I can only find the well-known call-cc technique (+ the amb function).

     What is the amb function?

     > But I meant something different: using recursive calls with a local

    > procedure as a parameter to the recursive call. See the example at the

    > end.

     Pretty sure that schemers would just cons up a list to remember the odd

    numbers rather than using the runtime stack. However, it would be possible

    to port it to Scheme fairly intact. I gave it a try:

    ;-------------------------------------------------

    (define (display-it n) (display n) (display " "))

    ; similar to Pascal version of oddeven without the console input

    (define (odd-even list)

      (define (space) (display "    "))

      (define (odd-dev list cp)

        (define n "?")

        (define (write-later) (cp) (display-it n))

        (if (null? list)

            (cp)

            (begin

              (set! n (car list))

              (if (even? n)

                  (begin (display-it n) (odd-dev (cdr list) cp))

                  (odd-dev (cdr list) write-later)))))

      (odd-dev list space))

    ; this version doesn't use recursive procedure parameters, it

    ; just constructs a list of the odds

    (define (odd-even-2 l)

      (define (odd-dev l odds)

        (if (null? l)

            (begin

              (display "    ")

              (for-each display-it (reverse odds)))

            (if (even? (car l))

                (begin (display-it (car l)) (odd-dev (cdr l) odds))

                (odd-dev (cdr l) (cons (car l) odds)))))

      (odd-dev l '()))

    (odd-even '(1 2 3 4 5 6 7 8 9))

    (display "\n")

    (odd-even-2 '(1 2 3 4 5 6 7 8 9))

    ;-------------------------------------------------

    I'm only new to Scheme so my code probably isn't as good as it could be.

    Steve.

## Ivan Tomac — 2003-03-19 08:33:43

    --- In concatenative@yahoogroups.com, Samuel Falvo <falvosa@y...>

    wrote:

     > > That has nothing to do with this. Defining new words in Forth is

     just

     > > like writing a library of functions in C. Neither breaks the

    > > language.

    >

    > It has everything to do with it; you suggested that my proposal to

     add words

     > which expose the dictionary in a more run-time accessible way would

     change the

     > language significantly to no longer be considered Forth.  This is,

     of course,

     > false, as CREATE and : are themselves already built up upon such

     functionality.

     >  My concern is that such functionality isn't made public (much less

     portable)

     > to the programmer, which severely hinders certain types of

     metaprogramming

     > under Forth.

    >

    > > If however a newly defined word replaces, breaks or modifies the

    > > behaviour of existing words as defined by a standard then you do

     end

     > > up with a new language or at least a new dialect - even more so

    > > since Forth itself doesn't have any reserved words and allows you

     to

     > > modify and change anything you want. Making Forth dictionary a

     first

     > > class object would change the behaviour of many Forth words and

    > > hence change Forth itself unless you created a new set of words

     to

     > > manipulate that dictionary and unless that dictionary was

     separated

     > > from the standard dictionary.

    >

    > I asked you once before for a proof of this, and I'm going to ask

     you again.

     > Until I see a definite proof, I cannot and will not accept this

     assertion.

     >

     I thought it would have been pretty obvious. Let's start with an easy

    example. Take a language like C, replace reserved words like if,

    else, switch, etc. with something like foo, moo, blurp, etc. (or even

    better switch them around so that if is else, else is switch, switch

    is for and for is if) The language you end up with won't be C

    anymore. It's structure will be identical to C and programming in it

    will be identical to C as well but it won't be able to compile C

    programs anymore. It could be described as a dialect of C but it's

    definitley not C anymore.

    Same thing happens with Forth, if you add words that modify or break

    the behaviour of existing words then that Forth interpreter/compiler

    won't be able to properly interpret other Forth programs. It's as

    simple as that.

    The more things you change/break, the less will the system behave

    like a standard Forth system. Making the dictionary a first class

    object and adding the ability to create words at run-time is a pretty

    big change - enough to break a whole bunch of programs previously

    written for that Forth system. Not to mention that programming in

    such a system would be completely different than normal Forth since

    you could create words that create other words at run-time and do all

    sorts of things that you just can't do with Forth. Sure it would be

    some dialect of Forth just like Objective C is still a dialect of C

    but it wouldn't be Forth anymore.

    I'm getting tired of this argument - it's pretty straight forward

    that if you break the existing constructs of a language you end up

    with a new language.

     > > them stand out from normal words. Again I should point out the

    > > similarities between defining and immediate words and

     preprocessor

     > > macros.

    >

    > You say this as if it were somehow ignored by me.  As the author of

     several

     > Forth implementations, and one more coming shortly, I can assure

     you that I

    I've written a few Forth implementations myself - not a big deal -

    Forth is one of the simplest languages to implement.

     > know full well the differences and similarities between

     preprocessor macros and

     > immediate words.  However, it is not at all relavent to the issue.

    >

     Well you seem to ignore what I said about colors. There is a reason

    why Chuck Moore decided to make the defining words of different

    color. It's because they do not behave like normal words. It is

    because conceptually they are not the same as standard Forth words.

    It is because they are generally executed at compile time and not run-

    time.

    Please read my first post again. You commented how CREATE does not

    take it's input from the program but the input stream. In my reply I

    stated that that I see defining words as a part of a separate

    language that exists in symbiosis with Forth and has many

    similarities with preprocessor macros. Chuck Moore seems to think the

    same although he might not word it in the same way. So it is actually

    very relevant to the issue.

    If CREATE did take it's input from the program you'd be able to

    create words at run-time and like I already stated the whole approach

    to programming in this new Forth-like language would be different

    (possibly somewhere half way between Joy and Forth or quite probably

    very similar to what an older version of my programming language,

    Meta/4, used to be like).

    Ivan

## Samuel Falvo — 2003-03-19 17:00:07

    > Same thing happens with Forth, if you add words that modify or break

    > the behaviour of existing words then that Forth interpreter/compiler

    > won't be able to properly interpret other Forth programs. It's as

    > simple as that.

     You're begging the question here.  I said *nothing* about changing the existing

    functionality of ANSI-defined words.

     > The more things you change/break, the less will the system behave

     You are confusing "changing" with "adding."  I never said that I'd get rid of

    CREATE, :, VARIABLE, or other similar defining words.  I *did* say that the

    words *THESE WORDS DEPEND ON*, the words that accept a word's name given a

    string on the stack (versus in the input stream), would be exposed to the

    programmer.  I cannot fathom as to how much more plain I can make this.

     > like a standard Forth system. Making the dictionary a first class

    > object and adding the ability to create words at run-time is a pretty

    > big change - enough to break a whole bunch of programs previously

     No it isn't.  Forth does it all the time.  In GForth:

      see create

      : Create

        header reveal dovar: cfa,  ;  ok

      see header

      : input-stream-header

        name name-too-short? header, ;

      lastxt

      Defer (header)

      IS (header)

      lastxt

      Defer header

      IS header  ok

      see header,

      : header,

        name-too-long? align here Last ! current @ 1 or , string, maxalign

    alias-mask lastflags cset ; ok

    What's wrong with exposing "header," to the programmer in a nice, portable

    fashion?  How can that possibly change the language so catastrophically as to

    not be Forth anymore?

     > written for that Forth system. Not to mention that programming in

    > such a system would be completely different than normal Forth since

    > you could create words that create other words at run-time and do all

    > sorts of things that you just can't do with Forth. Sure it would be

     Umm...EVALUATE?

    S" : blah  1 2 + . ;" EVALUATE

    blah

    The interface is ugly, and therefore, grossly inconvenient when you want to

    have a single word create a bunch of similarly defined words.  But it *IS*

    possible to do such things in modern Forth environments.

    All my suggestion does is ease the interface for the programmer, so that string

    manipulation, which Forth is patently poor at, doesn't need to happen.

     > I'm getting tired of this argument - it's pretty straight forward

    > that if you break the existing constructs of a language you end up

    > with a new language.

     Only,

    (a) you haven't proved how my suggestion would break Forth's existing

    constructs, and,

    (b) you've attempted to change the argument via non-sequitors and begging the

    question, and finally,

    (c) I've proven conclusively above that you needn't change the semantics of the

    language by exposing words which enable programmatic manipulation of the

    dictionary.

    At this point, I now believe you cannot establish such a proof, because one

    does not exist.

     > Well you seem to ignore what I said about colors. There is a reason

     No, I directly addressed the issue of colors by bringing up modality in the

    language.  You apparently seemed to have forgotten that.

     > Please read my first post again. You commented how CREATE does not

    > take it's input from the program but the input stream. In my reply I

    > stated that that I see defining words as a part of a separate

    > language that exists in symbiosis with Forth and has many

    > similarities with preprocessor macros. Chuck Moore seems to think the

    > same although he might not word it in the same way. So it is actually

    > very relevant to the issue.

     Please read my first post on the subject again, where I distinctly said nothing

    about *replacing* words like CREATE and :, but only *exposing* (that is,

    *adding* to the programmer visible and documented wordset) the words that

    enable programmatic manipulation of the dictionary.  You seem to have missed

    this very, very, very fundamental distinction in *ALL THREE* of the messages

    that I've written on the subject.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!

    http://platinum.yahoo.com

## phimvt@lurac.latrobe.edu.au — 2003-03-20 00:49:40

    On Tue, 18 Mar 2003, Samuel Falvo wrote:

     > OK, here's the Oberon program I've written:

     [.. translation from the Pascal version ..]

     > While the syntax of the compiler fully supports the notation of recursively

    > invoking inner functions, and passing them around as procedure pointers, the

    > oo2c compiler does not permit this.

     I feared that much.

     >                                       However, if oo2c were to implement

    > trampolines like GCC does for references to inner procedures, then there's no

    > reason why Oberon shouldn't support the feature.  However, issues of

    > type-safety come into play when doing this, which is presumably why Oberon

    > doesn't permit this construction.

     No, I do not think type-safety is the reason. After all, at least the

    original DEC Pascal compilers did very rigorous type-checking. (For

    an example - if you can stomach it - see the instance of fourth order

    recursion in the Appendix part 4.) It has to do with passing on the

    static chain, which is not trivial.

     > Shucks.  Oh well...

     In case it is not entirely obvious: none of this should deter anyone

    from implementing Joy in Oberon, since such an implementation would

    not need backtracking at all.

      - Manfred

## phimvt@lurac.latrobe.edu.au — 2003-03-20 01:23:14

    On Wed, 19 Mar 2003, Steven Shaw wrote:

     > What is the amb function?

     Actually I was careless - it is not a function but a special form

    defined as a macro. A good exposition is in (the book ?)

           Teach Yourself Scheme in Fixnum Days

    find it by Google search: "scheme fixnum amb" (That's Ch 14).

    Very briefly:    (amb 1 42 7)  returns 1 (and continues),

    and if that fails it backtracks and returns 42 (and continues),

    and if that fails it backtracks and returns 7 (and continues),

    and eventually fails.

     > > But I meant something different: using recursive calls with a local

    > > procedure as a parameter to the recursive call. See the example at the

    > > end.

    >

    > Pretty sure that schemers would just cons up a list to remember the odd

    > numbers rather than using the runtime stack.

     Yes, of course. And in Pascal one would use an array. The point

    was to find  *very* simple example of second order recursion.

    There are more useful ones in the later chapters.

     >                                     However, it would be possible

    > to port it to Scheme fairly intact. I gave it a try:

    >

    > ;-------------------------------------------------

    > (define (display-it n) (display n) (display " "))

    >

    > ; similar to Pascal version of oddeven without the console input

    > (define (odd-even list)

    >   (define (space) (display "    "))

    >   (define (odd-dev list cp)

    >     (define n "?")

    >     (define (write-later) (cp) (display-it n))

    >     (if (null? list)

    >         (cp)

    >         (begin

    >           (set! n (car list))

    >           (if (even? n)

    >               (begin (display-it n) (odd-dev (cdr list) cp))

    >               (odd-dev (cdr list) write-later)))))

    >   (odd-dev list space))

     Looks good. I take it the same thing would work in Common Lisp,

    ML, Haskell ... ?

    Also, in such languages in which functions are first class citizens

    (unlike Pascal), it should be possible to eliminate the definition

    of writelater, and replace its use (as a parameter) in the second last

    line:

                     (odd-dev (cdr list) (lambda (cp) (display-it n)))))))

    (or something like that). Would you care to try ?

    [...]

    Thanks for that.

      - Manfred

## Samuel Falvo — 2003-03-20 01:58:12

    > No, I do not think type-safety is the reason. After all, at least the

    > original DEC Pascal compilers did very rigorous type-checking. (For

    > an example - if you can stomach it - see the instance of fourth order

    > recursion in the Appendix part 4.) It has to do with passing on the

    > static chain, which is not trivial.

     Oberon's type safety is even stricter than that of Pascal.  See the Oberon

    Language Report.  This is, in fact, why I declared the callback as a separate

    type; had I not done so, Oberon's compiler would have complained about

    mismatched types, despite "appearing" to be the same.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!

    http://platinum.yahoo.com

## Steven Shaw — 2003-03-20 13:39:07

    > > What is the amb function?

    >

    > Actually I was careless - it is not a function but a special form

    > defined as a macro. A good exposition is in (the book ?)

    >        Teach Yourself Scheme in Fixnum Days

    > find it by Google search: "scheme fixnum amb" (That's Ch 14).

    > Very briefly:    (amb 1 42 7)  returns 1 (and continues),

    > and if that fails it backtracks and returns 42 (and continues),

    > and if that fails it backtracks and returns 7 (and continues),

    > and eventually fails.

     Found it. Wow, it's pretty wierd. Thanks.

     > > > But I meant something different: using recursive calls with a local

    > > > procedure as a parameter to the recursive call. See the example at the

    > > > end.

    > >

    > > Pretty sure that schemers would just cons up a list to remember the odd

    > > numbers rather than using the runtime stack.

    >

    > Yes, of course. And in Pascal one would use an array. The point

    > was to find  *very* simple example of second order recursion.

    > There are more useful ones in the later chapters.

     Ok, no worries. Could you point me towards one of those examples?

     > Looks good. I take it the same thing would work in Common Lisp,

    > ML, Haskell ... ?

     Yes. Common Lisp has first class functions but not first class

    continuations.

    ML is the same (but SML/NJ has call/cc). Not sure sure about

    Haskell...getting it to output something is just so damn hard! I think it

    would be harder to do in Haskell because the algorithm relies on

    side-effects (outputting even numbers as you go). Could be wrong.

     > Also, in such languages in which functions are first class citizens

    > (unlike Pascal), it should be possible to eliminate the definition

    > of writelater, and replace its use (as a parameter) in the second last

    > line:

    >                  (odd-dev (cdr list) (lambda (cp) (display-it n)))))))

    > (or something like that). Would you care to try ?

     Yes, that works.

    Cheers,

    Steve.

## Serguey Zefirov — 2003-03-21 01:28:37

    Hello Steven,

    Thursday, March 20, 2003, 5:39:07 AM, you wrote:

     >> Looks good. I take it the same thing would work in Common Lisp,

    >> ML, Haskell ... ?

     SS> Yes. Common Lisp has first class functions but not first class

    SS> continuations.

    SS> ML is the same (but SML/NJ has call/cc). Not sure sure about

    SS> Haskell...getting it to output something is just so damn hard! I think it

    SS> would be harder to do in Haskell because the algorithm relies on

    SS> side-effects (outputting even numbers as you go). Could be wrong.

    You may just use lazy evaluation in Haskell. And your pure functional

    program can be a function from input String to output String. That's

    the way old Haskell IO system worked.

    Some time (about two year and half) ago I posted Haskell source for

    Joy interpreter. I downloaded it from Yahoo Groups and after some

    editing (yahoo broke the layout) it worked fine, giving me:

    Joy> test

    "test!"

    1967 reductions, 4559 cells.

    Look at it here:

    http://groups.yahoo.com/group/concatenative/message/471

    It is just core of interpreter encoded in Monad and lacks real Joy

    syntax parser.

    Actually, I still learning functional languages and programming, so I

    can be wrong, but in lazy language you can encode ((in)effeciently)

    continuation based program into more straightforward one (most of the

    time;).

    Right now I think I've try to encode it in the Fudgets stream

    processors style:

    http://www.cs.chalmers.se/Fudgets

    to learn them better. ;)

    And, after all, "getting it to output something is just so damn hard"

    is Haskell greatest strength. ;)

    --

    Best regards,

     Serguey                            mailto:sz@...

## phimvt@lurac.latrobe.edu.au — 2003-03-24 04:27:14

    On Thu, 20 Mar 2003, Steven Shaw wrote:

     > > Yes, of course. And in Pascal one would use an array. The point

    > > was to find  *very* simple example of second order recursion.

    > > There are more useful ones in the later chapters.

    >

    > Ok, no worries. Could you point me towards one of those examples?

      http://www.latrobe.edu.au/philosophy/phimvt/s00bok.html

    Chapter 8 for illustrations, then Ch 9 10 11 15 16 20 for real uses,

    and Appendix part 4 "Fourth order recursion" for an extreme app.

     > > Looks good. I take it the same thing would work in Common Lisp,

    > > ML, Haskell ... ?

    >

    > Yes. Common Lisp has first class functions but not first class

    > continuations.

    > ML is the same (but SML/NJ has call/cc). Not sure sure about

    > Haskell...getting it to output something is just so damn hard! I think it

    > would be harder to do in Haskell because the algorithm relies on

    > side-effects (outputting even numbers as you go). Could be wrong.

     Use a list [1 2 3 4 5 6 7 8 9] as input, produce a list

    with separator [1 3 5 7 9 999999 2 4 6 8] as output.

    Or maybe the reverse (obtained by consing) would be

    easier: [8 6 4 2 999999 9 7 5 3 1]. Only a "proof of concept"

    is called for here.

     > > (unlike Pascal), it should be possible to eliminate the definition

    > > of writelater, and replace its use (as a parameter) in the second last

    > > line:

    > >                  (odd-dev (cdr list) (lambda (cp) (display-it n)))))))

    > > (or something like that). Would you care to try ?

    >

    > Yes, that works.

     Thanks.

      - Manfred

## Steven Shaw — 2003-03-24 07:11:00

    > > Ok, no worries. Could you point me towards one of those examples?

    >

    >  http://www.latrobe.edu.au/philosophy/phimvt/s00bok.html

    > Chapter 8 for illustrations, then Ch 9 10 11 15 16 20 for real uses,

    > and Appendix part 4 "Fourth order recursion" for an extreme app.

     Thanks. The entire book looks very interesting!

## Steven Shaw — 2003-03-24 15:46:39

    > > Yes. Common Lisp has first class functions but not first class

    > > continuations.

    > > ML is the same (but SML/NJ has call/cc). Not sure sure about

    > > Haskell...getting it to output something is just so damn hard! I think

     it

     > > would be harder to do in Haskell because the algorithm relies on

    > > side-effects (outputting even numbers as you go). Could be wrong.

    >

    > Use a list [1 2 3 4 5 6 7 8 9] as input, produce a list

    > with separator [1 3 5 7 9 999999 2 4 6 8] as output.

    > Or maybe the reverse (obtained by consing) would be

    > easier: [8 6 4 2 999999 9 7 5 3 1]. Only a "proof of concept"

    > is called for here.

     I mangaged to get it going in Haskell both using side effects (outputting as

    it goes) and returning a list as you suggested. To my surprise it turned out

    to be easy to implement with side effects. I tried a couple of different

    techniques for functions returning lists but I don't think these functions

    maintain the "second order recursion".

    Here is the side effecting version using second order recursion:

    oddEven2 list = let

      aux (x:xs) cp =

        if (even x) then

          do output (show x); aux xs cp

        else

          aux xs (do cp; output (show x))

      aux [] cp = cp

      in do

        aux list (output "....")

        out "\n"

    The main problem with Haskell seems to be obsure error messages (always

    typing errors) often far away from the cause. In versions creating lists, I

    found that I couldn't cons things together with :: but instead had to use

    string append (++) because of some typing error (that probably leads to

    poorer performance).

    Steve.

    [Non-text portions of this message have been removed]

## Steven Shaw — 2003-03-24 16:14:16

    Here is the full code as the attachment was deleted:

    --Main.hs ------------------------------------------------------------------

    --

    import IO

    out = hPutStr stdout

    output x = do out x; out " "

    foreach (x:xs) f = do f x; foreach xs f

    foreach [] f = out ""  -- how to do nothing?

    main =

      let list = [1..9]

      in do

        out "list with print = "; print list

        out "list with foreach = "; foreach list (\x -> output (show x)); out

    "\n"

        out "version 1 = "; print (oddEven1 list)

        out "version 2 = "; oddEven2 list

        out "version 3 = "; print (oddEven3 list)

        out "version 4 = "; oddEven4 list

    -- not using recursive local functions, returns list

    oddEven1 list = let

        aux (x:xs) odds =

          if (even x) then

            [x] ++ (aux xs odds)

          else

            (aux xs ([x] ++ odds))

        aux xs odds = [999999] ++ (reverse odds)

        in aux list []

    -- uses recursive local functions, outputing as it goes

    oddEven2 list = let

      aux (x:xs) cp =

        if (even x) then

          do output (show x); aux xs cp

        else

          aux xs (do cp; output (show x))

      aux [] cp = cp

      in do

        aux list (output "....")

        out "\n"

    -- like oddEven1 but in same style as the recursive local

    oddEven3 list = let

      aux (x:xs) cp =

        if (even x) then

          [x] ++ (aux xs cp)

        else

          aux xs (cp ++ [x])

      aux [] cp = cp

      in aux list [999999]

    -- remembers the odds, outputs as it goes

    oddEven4 list = let

      aux (x:xs) odds =

        if (even x) then

          do output (show x); aux xs odds

        else

          aux xs (odds ++ [x])

      aux xs odds = do

        output "...."

        foreach odds (\x -> output (show x))

      in do

        aux list []

        out "\n"

    ----------------------------------------------------------------------------

    --

    Here is the output produced:

    ----------------------------------------------------------------------------

    --

    list with print = [1,2,3,4,5,6,7,8,9]

    list with foreach = 1 2 3 4 5 6 7 8 9

    version 1 = [2,4,6,8,999999,1,3,5,7,9]

    version 2 = 2 4 6 8 .... 1 3 5 7 9

    version 3 = [2,4,6,8,999999,1,3,5,7,9]

    version 4 = 2 4 6 8 .... 1 3 5 7 9

    ----------------------------------------------------------------------------

    --

## John Cowan — 2003-03-24 18:21:28

    phimvt@... scripsit:

     > PROGRAM oddevn(input,output);

     I translated the program into GNU C (it will not work in ANSI C, of course):

    ===== cut here =====

    # include <stdio.h>

    typedef void (*proc)();

    int eoln() {

    	int i;

    	i = getchar();

    	if (i == '\n') return 1;

    	ungetc(i, stdin);

    	return 0;

    	}

    int eof() {

    	int i;

    	i = getchar();

    	if (i == EOF) return 1;

    	ungetc(i, stdin);

    	return 0;

    	}

    void space() {

    	printf("    ");

    	}

    void odev(proc cp) {

    	int n;

    	void writelater() {

    		cp();

    		printf("%d ", n);

    		}

    	if (eoln()) cp();

    	else {

    		scanf("%d", &n);

    		if (n % 2 == 0) {

    			printf("%d ", n);

    			odev(cp);

    			}

    		else

    			odev(writelater);

    		}

    	}

    int main() {

    	while (!eof()) {

    		odev(space);

    		printf("\n");

    		}

    	}

    ===== cut here =====

     > It would be of interest to me to know whether gcc can handle

    > this sort of thing (as I mentioned before, the version of p2c

    > that I once tried failed.)

     It works, most definitely.  It took a bit of debugging to get right, basically

    because of oversights in my hand-translation, and I had to research the

    semantics of eoln and eof in Pascal to realize that they involve lookahead.

    --

    In politics, obedience and support      John Cowan <jcowan@...>

    are the same thing.  --Hannah Arendt    http://www.ccil.org/~cowan

## phimvt@lurac.latrobe.edu.au — 2003-03-27 05:47:28

    On Mon, 24 Mar 2003, John Cowan wrote:

     > phimvt@... scripsit:

    >

    > > PROGRAM oddevn(input,output);

    >

    > I translated the program into GNU C (it will not work in ANSI C, of course):

    >

    > ===== cut here =====

     [...]

     > ===== cut here =====

     [...]

     > It works, most definitely.  It took a bit of debugging to get right, basically

    > because of oversights in my hand-translation, and I had to research the

    > semantics of eoln and eof in Pascal to realize that they involve lookahead.

     Thank you very much. This will save me from teaching my students

    the other two (very ugly) methods that I eventually got to work

    for translating my backtracking programs in Pascal into (K&R)C:

    1) [unportable, I am sure] pass on an extra parameter which is the

       beginning of the current activation record, or

    2) [portable, but combersome] an explicit stack of continuations.

    Also, it gives me some motivation to translate the later ones

    into GCC ... (they are too large to expect my students to do them).

    Thanks again.

      - Manfred

## Samuel Falvo — 2003-03-27 07:43:54

    > 2) [portable, but combersome] an explicit stack of continuations.

     I'm curious if this realization is what led to your research in creating Joy?

    That is, if you're going to manipulate a stack of continuations manually and

    explicitly, why not design the whole langauge around it?  Just wondering.

    --

    Samuel A. Falvo II

    __________________________________________________

    Do you Yahoo!?

    Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop!

    http://platinum.yahoo.com

## phimvt@lurac.latrobe.edu.au — 2003-04-01 03:26:30

    On Wed, 26 Mar 2003, Samuel Falvo wrote:

     > > 2) [portable, but combersome] an explicit stack of continuations.

    >

    > I'm curious if this realization is what led to your research in creating Joy?

     No, no connection at all. In fact, the prehistory of Joy

    is mercifully shrouded in the mists of time.

      - Manfred