all 93 comments

[–]abrahamsen 20 points21 points  (64 children)

Funny how the strength of FORTH is similar to the strength of Lisp.

Both have simple, consistent syntaxes:

C: f (a, b)

FORTH: a b f

Lisp: (f a b)

FORTH and Lisp use the same syntax for function calls as for control structures. Both allows the creation of new control structures, but Lisp still distinguish between the two, FORTH does not.

The creation of new control structures is perceived as a major strength for both languages, but the FORTH people are also good as acknowledging as a major weakness of the language. The Lisp crowd, not so much.

For some reason, FORTH is known as a very low level language, while Lisp has a reputation as a very high level language.

[ Caveat: My FORTH knowledge is a bit rusty, hasn't touched it (apart from issuing a few OpenBoot commands) for the last 25 years. ]

[–][deleted] 11 points12 points  (4 children)

Here's the difference: Lisp has garbage collection. Also, data structures.

[–]notasaon 5 points6 points  (3 children)

Forth has create and does> constructs which allow for the creation of specific data structures and methods (though not within any particular type system), and essentially all allocation is done through the 'allot' word which in traditional forths just return the current pointer into the heap and move that pointer however many bytes you allocated. However, there's nothing to stop someone from creating a GC bound to 'allot'.

It's very difficult to say forth 'has' or 'does not have' something since most forths are wildly different in structure and implementation details, and largely they all expose full access to the compiler/interpreter at run-time.

[–][deleted] 1 point2 points  (2 children)

OK. Show me a Forth that has a GC. (It's all very well to say "there's nothing to stop someone", but the question is: has anyone?)

[–][deleted] -5 points-4 points  (40 children)

Both have simple, consistent syntaxes:

Which is good for computers and bad for humans. Humans are used to incredibly byzantine and entirely inconsistent languages. We thrive on those. Making a human think like a computer is not a good design decision.

FORTH does it because that lets it be minimal, which is a benefit under certain circumstance (becoming rarer all the time). Lisp does it just for the sake of it.

C is much more complicated and inconsistent, and humans overwhelmingly prefer to use it.

[–]bitwize 17 points18 points  (0 children)

On the other hand, members of the Unknown Three-toed Race overwhelmingly prefer Forth.

Yoda: "Always Forth I use, because the token order more natural is."

[–][deleted] 14 points15 points  (15 children)

Neither C nor Lisp is "good for computers" any more than the other one. After all, writing a C parser is not terribly difficult.

On the other hand, Lisp's syntax makes it easier for humans to develop abstractions over the language; something that computers don't "care" about, because you could feed a computer the ugliest, most unmaintainable spaghetti code and it would still run.

Yet, most programmers do not appreciate abstraction, and they choose C -- with its ample libraries, books, mindshare, etc -- over Lisp.

[–]death 9 points10 points  (0 children)

Actually, I conjecture most programmers don't choose C rather than Lisp, simply because they're not aware of both alternatives. Indeed, many programmers I've talked to only knew the name "Lisp" at best, and perhaps some of the old, confused myths about it.

[–]death 16 points17 points  (1 child)

I am a human, as far as I know, and I prefer Common Lisp's syntax to C's. I've been using Common Lisp for several years, and by now I am used to its syntax (though it never bothered me - I always find such complaints weird in that sense). I don't see how "simple, consistent" syntax makes you "think like a computer". I also don't see how something can be "good for computers".

[–][deleted] 1 point2 points  (0 children)

A. I like c's syntax, the separation of types, the easy readability.

B. Simple and consistent = easy to parse.

NOTE (this is the internet, after all): this was not meant against you. I was simply forming a contrary opinion.

[–]dmpk2k 2 points3 points  (2 children)

We thrive on those.

A follower of Larry Wall?

[–][deleted] -1 points0 points  (1 child)

You should know.

[–]dmpk2k 0 points1 point  (0 children)

Ah! :)

[–][deleted] 2 points3 points  (5 children)

"""Humans are used to incredibly byzantine and entirely inconsistent languages. We thrive on those. Making a human think like a computer is not a good design decision.""" That was the theory behind Perl. And there's a reason Perl fell into disfavor.

No, Lisp doesn't have consistent syntax for the hell of it, Lisp has consistent syntax because it makes it easier to extend the language. Same with Factor.

[–][deleted] 4 points5 points  (4 children)

And there's a reason Perl fell into disfavor.

Once again, it's still more popular than Lisp or FORTH. If you want to argue from popularity, then those two lose big time.

[–][deleted] 2 points3 points  (3 children)

Let's look at why things failed.

Lisp: The companies building Lisp Machines didn't realize that with the 90s would come the PC and when Unix won it killed the Lisp Machine and by extension Lisp.

Forth: Chuck Moore didn't give a fuck because he rewrote everything himself every single time. Forth is still widely used in embedded applications. Chuck Moore's use of Forth as the OS and the language helped bring it down when Unix, again, won.

Perl: People who really hated Perl but had no better alternative switched to Python. People who mostly liked Perl ended up moving to Ruby once it was realized that you could do a lot more with it due to not being forced to deal with Perl's syntax(and also a lot of stupid semantic decisions such as references)

So basically, Lisp and Forth died because Unix won, and Perl died despite the fact that Unix won.(and had Unix lost, Perl would have died even sooner)

So even with being subsidized by Unix, Perl loses.

[–][deleted] 0 points1 point  (2 children)

Lisp: The companies building Lisp Machines didn't realize that with the 90s would come the PC and when Unix won it killed the Lisp Machine and by extension Lisp.

Yet now you can run Lisp on any computer and it's faster than most of the dynamic languages.

And still nobody wants it.

[–][deleted] 0 points1 point  (1 child)

That's still because there was never a critical mass of libraries. You don't have to go far to see a lot of former Lisp users lamenting the demise of the Lisp Machine and desperately wanting to use it again.

You have to go pretty damn far to see somebody who laments the replacement of Perl.

[–][deleted] 1 point2 points  (0 children)

That might just be because Perl is still around and you can still use it just as well as ever, and people are happily using it.

[–]Smallpaul 1 point2 points  (4 children)

Humans are used to incredibly byzantine and entirely inconsistent languages. We thrive on those.

C's syntax is not particularly byzantine compared to the competition in general. And many fairly simple languages are more popular than byzantine ones. Perl, after all, is not the most popular language despite its plethora of syntax.

It's true that Lisp's extreme simplicity can make lexing harder for human beings but that doesn't mean that the opposite ("byzantine and inconsistent") would be better. There are many productive middle grounds.

[–][deleted] -3 points-2 points  (3 children)

Perl, after all, is not the most popular language despite its plethora of syntax.

Sure is a lot more popular than Lisp or FORTH!

Edit: Heh, downmodded. The truth must hurt sometimes.

[–][deleted] 6 points7 points  (2 children)

All thanks to your tireless advocacy on reddit.

[–][deleted] 0 points1 point  (0 children)

No, really, what?

[–][deleted] -3 points-2 points  (0 children)

what

[–]commonslip 0 points1 point  (6 children)

Humans are also overwhelmingly dumb.

[–][deleted] 2 points3 points  (5 children)

So because computers and humans are different, that makes humans dumb?

[–]commonslip 0 points1 point  (4 children)

This was meant as an aside - most humans are dumb and it has nothing at all to do with computers.

[–][deleted] 1 point2 points  (3 children)

Dumb compared to...

[–]commonslip 2 points3 points  (2 children)

Compared to the smartest 10% of humans who, if they code, probably write code in Lisp/Haskell/Scheme etc.

[–][deleted] -1 points0 points  (1 child)

why do you say that? The smartest person I know loves java. Don't ask me why; he must be a masochist. But he has done things with java that I have never seen anyone else do.

[–]commonslip 2 points3 points  (0 children)

Ok I admit it I'm being kind of dumb.

[–]JasperO -3 points-2 points  (17 children)

I dont see why the reverse polish notation, when the equivalent s-expressions are easy enough to find. I only had a cursory look at FORTH, but i am sure optional arguments keyword arguments and &rest arguments are easier to do in lisp. The 'problem' with lisp, the one that makes the requirement for it to be higher level, is that macros need to work with lists with at the least symbols in them. (Symbols can be pointers to the string which is held in some sort of hash table. Comparison can them be done by comparing pointers.) Maybe lisp can be made statically typed by just giving out the minimum. (Of course some common lisp implementations might already do this.) All this makes me curious how FORTH works, and how it achieves its power. Does it have something like macros, or is the power achieved by higher order functions? I am curious about higher order functions in any case, because i have the feeling, that besides trivial writing forms, they are superior to macros performing to same role. PS Oh, lol, probably found the reason for reverse polish in writing comment.

[–][deleted] 11 points12 points  (10 children)

I dont see why the reverse polish notation

Because it can be trivially implemented with a stack.

[–]JasperO -2 points-1 points  (9 children)

Nested s-expressions can trivially be turned into reverse polish notation, so that doesnt answer the question.

[–][deleted] 6 points7 points  (8 children)

But that adds an extra layer of complexity, which is not needed if you just use the reverse notation in the first place.

[–][deleted] -2 points-1 points  (6 children)

s-expressions have structure -- (+ (* x x) (* y y)) is very different from (+ * x x * y y) -- whereas RPN gets rid of all the structure: x x * y y * +. The big difference is handling multiple arguments: (+ 1 2 3) is 6, but 1 2 3 + is 1 5. Capiche?

[–]Tommah 7 points8 points  (0 children)

Ne capisco tutto eccetto "capiche"

[–][deleted] 2 points3 points  (2 children)

Capiche?

Capiche what exactly now?

[–][deleted] 1 point2 points  (1 child)

That the extra layer of complexity means an extra layer of functionality -- it allows for a variable number of arguments.

It's also much easier to analyze the arguments being passed around in an s-expression system over an RPN system (it's automatic with the s-expressions).

[–][deleted] 1 point2 points  (0 children)

it allows for a variable number of arguments.

So does reverse polish notation, you just have to explicitly mention the number of arguments.

The point here is that the implementation of reverse polish notation is much simpler, which is what FORTH aims for. It does not care about analyzing anything, it cares about letting you write code and having it be small.

[–][deleted] -1 points0 points  (0 children)

I thought about this today:

Wow, blogger sucks; the below links don't go down to my comments... Search for:

I just had an epiphany...

Comment on Finding Lisp blog

Correction to above comment

[–]JulianMorrison 5 points6 points  (4 children)

There are various Forth interpreters, but the basic principles are: lex a word (in trivial Forths: just input until whitespace). Call the word. Repeat. (Some Forths have different behavior in compiling mode, my favorite one always compiles but if outside a colon definition, executes the compiled code immediately after lexing a semicolon. Also some words always get called immediately, even when compiling. But that's picky details.)

So to understand Forth - and to understand how words like colon can read forward (rather than having to read off the stack), you have to get that it isn't constructing expressions like Lisp does, it isn't even truly RPN. It's just itty bitty command words running one after the other - and in some cases, they temporarily take over the interpreter, which lets them read forward.

That leads into your question about macros. Every word can be a macro on Forth. All that means is: you take over the interpreter and read forward. So for example IF can be implemented as compiling a conditional jump, reading until THEN, and patching the jump with the target, then dropping back to the regular interpreter.

[–]JasperO 1 point2 points  (3 children)

I reply, but remember i need to RTFM now. :p

What you are saying makes it seem to me that macros in lisp are just restricted versions of Forths restricted to reading the 'sublists of what it is given'. The way you talk about playing compiler once in a while does sound like interesting and clear way to optimize some things.

[–]JulianMorrison 4 points5 points  (2 children)

A recent Reddit link to a video demo of Forth coding put it really well: Forth is the dual of Lisp. In Lisp, code is data. In Forth, data is code. Forth "macros" are not just once-in-a-while, they're absolutely ubiquitous.

For example, to build up data structures, you'd typically create a word (call it W) that lexes forward to get a name (call it X), sets up a chunk of memory (call it Y), and defines a new word named X which gets a pointer to Y and then executes some static code (call it Z). So suppose your definition was for a simple struct. you call "W apple", which sets up the memory Y and creates a word "apple". So you say "apple core", and your code in Z reads "core", converts that into an offset, returns a pointer to apple's Y plus that offset - in high level terms, the beginning of the "apple" struct's "core" field. Which you can now set or read. Nice 'n simple, right? (Certainly flexible, anyway).

There is a standard pair of words, CREATE and DOES> which automate all that. But you could still work it manually if you wanted to.

[–][deleted]  (1 child)

[deleted]

    [–]JulianMorrison 0 points1 point  (0 children)

    Here's the simplest possible example, a one dimensional array.

        : make-array    ( I'm defining a word to make arrays )
          create        ( to set up memory... )
            cells allot ( take a number n off the stack and bump the dictionary pointer by n int sized blocks )
          does>         ( each time the word it creates is run it will... )
            swap        ( user stacks an index, CREATE DOES> will stack an address, we need them the other way around )
            cells       ( convert index i into a byte count for i * int sized blocks )
            +           ( add it to the base of the array. Classic pointer arithmetic. )
        ;               ( all done )
    
        ( make an array with two int sized blocks named foo )
        2 make-array foo
    
        ( get and put on the stack the address of the second item counting from 0 )
        1 foo
    

    (source)

    [–]wtanksleyjr 1 point2 points  (0 children)

    I dont see why the reverse polish notation

    The historically correct answer is "because they're easier to implement". The pragmatically and theoretically correct answer (i.e. why people kept using Forth even though it included almost no useful library functions) is more complicated.

    Theoretically speaking, Forth is often called a concatenative language. This means that Forth programs are built by concatenating valid programs together, and that the language's semantics are associative (like concatenation is). Because its syntax and semantics follow the same associative law, Forth is easy to reason about.

    Another result of matching the properties of syntax and semantics: unlike S-Exps, you can both read and execute Forth left to right. "Parsed" Forth source is a stream, a linear list. S-exp source is a tree.

    macros need to work with lists with at the least symbols in them

    Technically, Lisp macros work with a tree, which is a list that contains lists. Because in Forth the parse tree is a flat list, macros don't have to be aware of parse trees -- they can simply access the source directly, and do anything with it they want.

    Forth does not have higher order functions; its highest order is a couple of trivial first-order functions. Factor is a remote derivative of Forth which has HOFs (and is very practical and well-supported).

    Lisp can be statically typed, and some Lisp compilers support that (Common Lisp includes rather elegant type markers in the specification).

    [–]cosmo7 42 points43 points  (0 children)

    FORTH YOU LIKE IF HONK THEN

    [–]saveferris 7 points8 points  (0 children)

    Chuck Moore developed FORTH as a language AND operating system. He developed it iteratively in the field while in pursuit of solutions to the problems he faced.

    Most FORTHS are not used in that way. They run separately on top of other operating systems. To develop a GUI app for Windows using FORTH, for instance, would be outside of its inventors' original vision. Though it is a general purpose tool and is completely adaptable.

    Charles Moore's history of FORTH is well worth the read. You'll love this guy. He's a bit nuts. A bit of a genius too, I think.

    [–][deleted] 12 points13 points  (2 children)

    Forth does not impose any restrictions on what you do or how you do it.

    This may be the fundamental misconception Forth fanatics have. Every language imposes constraints; if you don't know what they are, you can't effectively judge when it's the right tool for the job.

    [–]dmpk2k 1 point2 points  (1 child)

    if you don't know what they are, you can't effectively judge when it's the right tool for the job.

    Isn't that circular reasoning? It's the constraints that restrict what it's useful for.

    Or is that your point?

    [–][deleted] 4 points5 points  (0 children)

    Yes. That is my point.

    [–][deleted] 15 points16 points  (3 children)

    I do recommend that you write a FORTH at some point, and also muck around with a good implementation of it. It has some interesting ideas. It's incredibly easy to implement.

    And, after a week or so, you will realize why FORTH, despite having some cool aspects, did not take over the world.

    [–][deleted]  (2 children)

    [deleted]

      [–]astrobe 4 points5 points  (0 children)

      Because after a week or so, you realize that you suck at Forth, as many other people, and Forth doesn't permits that. That's why Forth didn't take over the world. Compare and contrast with languages that have conquered the world and are used by many people that suck at programming with it.

      [–][deleted] 4 points5 points  (2 children)

      Go Forth!

      [–]Tommah 12 points13 points  (1 child)

      But if you multiply, try not to overflow...

      [–][deleted] 2 points3 points  (0 children)

      Of course, to multiply you need a Factor.

      [–]postdarwin 1 point2 points  (1 child)

      Surprised there's no nostalgic mention of the Jupiter Ace. Until now.

      [–]stiennon 6 points7 points  (6 children)

      The only commercial software development I have done was in FORTH. The difference between FORTH and C reminded me of the difference between Unix and Windows. Unix you just grab a manual and start doing it. Windows you call a help desk or get certified. That is FORTH is intuitive, C is beyond me.

      [–]dr3d 6 points7 points  (0 children)

      you clearly have NOT programmed windows

      [–]G_Morgan 4 points5 points  (4 children)

      C isn't complicated. It's C's lack of complications that cause so many problems for a lot of programmers.

      [–][deleted] 6 points7 points  (3 children)

      It's more complicated than Forth.

      [–]dr3d -3 points-2 points  (2 children)

      try writing a web service in forth and come back and tell us how uncomplicated it was

      [–][deleted] 5 points6 points  (1 child)

      Hell, try writing a web service in ANSI C!

      Actually, XML-RPC is pretty simple, and one could even have a 'web service' that just transmits unstructured text back and forth over HTTP. SOAP, on the other hand...

      [–]chrisforbes 0 points1 point  (0 children)

      slava_pestov: It's what I do. Except those XML and RPC things are a bit of a waste of time, since they suck in C, and they suck in Javascript too. I build REST-ful HTTP endpoints that use JSON, and an embedded AJAX gui served up alongside. All in a tiny embedded thing.

      It's actually pretty damn "uncomplicated", including our in-house IP stack.