> Forth is an assembly language for a pretty low level stack-based virtual machine. (And such machines are very popular, though rarely programmed by hand.)
Forth is indeed an assembly language for Forth processors, but Forth was never intended as some sort of intermediate language. It is a programming language for humans since 1970.
It's interesting to note that, unlike Lisp machines and other language-X-processors who are now rusting in museums, "Forth processors" are still being launched in space [1].
So, to anticipated about what you say later, it must be a cosmic buffoon. Better than dying from a slightly cold winter I guess.
> It's not a good VM for compiling dynamic languages
Off topic, but why would you do that anyway? At some point, register-based VMs outperformed stack-based VMs due to the evolution of processors (cache, branch prediction, large register banks) and progresses in compilation techniques.
Forth doesn't need to be "recycled" as a target language. It is useful enough for those who've practiced it long enough to understand its value proposition.
> Forth is completely forgiving, like an old buffoon. Pass four arguments to a three-argument function? All is forgiven.
Lua and Newlisp (and probably other Lisp variants) let you pass more arguments or less arguments to a function; you won't get any warning while the compiler/interpreter silently ignores the extra parameters or fills the missing parameters with nil.
In Forth there are some ways to detect argument mismatches, but really nobody cares about those training wheels. The problem is solved in a different way.
Also, many dynamic languages had to add a "strict mode" because letting people not declare identifiers is not so "user-friendly" after all...
I'll trade any day a language that breaks on stupid typos for a language that breaks because I forgot to push a result. Actually, that's why I did.
Using NewLisp as representative of Lisps is a strawman argument. It's a garbage project that is despised by anyone who is serious about Lisp.
ANSI Common Lisp and Scheme do not allow too many or too few arguments to be passed to a function.
Let's try CLISP:
[1]> (defun test () (cons 1 2 3))
TEST
[2]> (compile 'test)
WARNING: in TEST : CONS was called with 3 arguments, but it requires 2
arguments.
Or:
[3]> (defun test (x))
TEST
[4]> (compile 'test)
WARNING: in TEST : variable X is not used.
Misspelled or missing IGNORE declaration
Unbound vars:
[5]> (defun test (x) (+ x y))
TEST
[6]> (compile 'test)
WARNING: in TEST : Y is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
> nobody cares about those training wheels.
Error checking is for lesser programmers: very effective advocacy!
> The problem is solved in a different way
Exhaustive testing? The problem is that there isn't even a reliable dynamic check. A misuse of the data stack in one place can affect code elsewhere. Just because you step on the bug doesn't mean that the machine will halt with a diagnostic, let alone one that pinpoints the cause.
> Using NewLisp as representative of Lisps is a strawman argument. It's a garbage project that is despised by anyone who is serious about Lisp.
Well, your opinion about it has changed quite a bit... I still like it probably because I am less interested in "serious about Lisp" than in pragmatic solutions. The other day I shipped a small networking utility as two files: the standard newlisp.exe and a newlisp script. I used Newlisp instead of my equivalent written in Forth because the user may have needed to hack it a little bit. The instruction I had to give was "just copy that on your desktop and drag the script file to the exe file". Job: done. I count it as Lisp being useful in 2019.
Anyway, there's still dozens of scripting languages that won't move an eyebrow about bad arity.
>> nobody cares about those training wheels.
> Error checking is for lesser programmers: very effective advocacy!
Beginners are not lesser programmers, they are less skilled programmers. It's a temporary condition.
Also, I'm not advocating Forth. It hasn't caught in 40 years, so it is obviously not for everyone. I'm just clearing what I think is misunderstandings. Just like I would defend a show when I think some reviewer totally misunderstood it.
> Exhaustive testing?
Yes, this is one of the ways. Whether you use static, dynamic, or no type-checking that's something you do anyway when things get serious. Because none of them catch all bugs.
> The problem is that there isn't even a reliable dynamic check
Stack imbalances in practice catch half of the programming errors. It's a bit like in Haskell: if it compiles, it has good chances to be right. In Forth, it translates into: if the depth of the stack doesn't change in your main loop, the program is probably right.
> A misuse of the data stack in one place can affect code elsewhere.
Most often the program just segfaults right away, because you're manipulating pointers quite often. That's another 25% of errors caught.
> doesn't mean that the machine will halt with a diagnostic, let alone one that pinpoints the cause
Relying on stack dumps and debuggers is a terrible habit. Looking for the simplest way to solve a problem is far more effective globally.
I know this sounds insane. I was there decades ago. I built a Forth that couldn't possibly crash and was disappointed by the result. I built Forth debuggers and was also disappointed. I built support debugging primitives in VMs and I was disappointed. That's because I was trying to cure the symptoms instead of the illness. Then I started to throw away and rewrite when a piece of code was buggy. That helped a lot.
For one thing you get rid quickly of the "lets try this to see if it works" mentality, which is a recipe for bugs and half-baked code. "Do. Or do not. There is no try".
If debugging is the process of removing software bugs, then programming must be the process of putting them in.
-- Edsger Dijkstra
This guy was right. Studies have shown that the amount of bugs is proportional to the LOC count. The message is "Program less, think more", and this is also what Forth says:
You factor. You factor, you factor, you factor and you throw away everything that isn't being used, that isn't justified.
-- Chuck Moore, 1x Forth [1]
Basically that's "The simplest thing that can possibly work" [2] approach taken to the extreme. The thing is, being extreme is not easy. You can pick a low-hanging fruit or two by being audacious sometimes, but being extreme means climbing the tree to the top.
> Well, your opinion about it has changed quite a bit.
I'm not aware that I have held any other opinion about NewLisp at any time in the past.
The language described by ANS Forth not only doesn't have arity checking, it has no type checking. That is to say, the items on the data stack have no type: not run-time, not static. Two addresses could be pushed onto the stack, and then operated on as a double integer.
There is nothing wrong with that, just like there is nothing wrong with machine language instruction sets. We can write a compiler for a higher level language which compiles to ANS Forth, one that is considerably safe. There is value in that because we still have the benefit of portability, small run-time footprint and low resource use, depending on our application size.
Type, arity and other checking is not analogous to training wheels for beginners. Nobody believes nonsense like this once they are out of their programming puberty. I suspect you wouldn't say that in an interview, if you actually wanted the job.
> Most often the program just segfaults right away
If you're getting a "segfault" it's because you're running on a virtual memory system (likely written for you in a considerable amount of C).
Things don't always segfault right away. The problem can be in a conditional code that depends on particular kinds of inputs.
If you're having to trivial function arity mismatches with segfaults (when you have the luxury segfaults) is ridiculous, you can't simultaneously believe that you're working in a higher level language on par with Common Lisp or Scheme, or even ANSI C.
> Anyway, there's still dozens of scripting languages that won't move an eyebrow about bad arity.
And they are all garbage; so what? Many of these languages, however, will at least behave somewhat safely in the face of bad arity. That is to say, if there are insufficient arguments, those parameters get some default values, and excess arguments are ignored, without lingering around to cause a problem elsewhere.
> We can write a compiler for a higher level language which compiles to ANS Forth, one that is considerably safe
You are better off targeting some bytecode VM rather than targeting the Forth language itself. You can target for instance Lua Bytecode and still have all of the benefits.
> Type, arity and other checking is not analogous to training wheels for beginners. Nobody believes nonsense like this once they are out of their programming puberty. I suspect you wouldn't say that in an interview, if you actually wanted the job.
Well I used to believe it was nonsense too. Maybe I'm older that you. Or maybe I was more curious.
I would definitely mention the fact I can program in a point-free, type-less language. That's an additional skill, not a hindrance. I didn't have the chance to test this because I already have a programming job (where I use Forth for personal supporting tools that help dealing with the peculiarities of embedded systems or with the shortcomings of our official software - but don't tell anyone). What I wouldn't do is trying to sell something like Forth to an unknown team for an unknown project.
> If you're getting a "segfault" it's because you're running on a virtual memory system (likely written for you in a considerable amount of C).
Actually yes, it assumes the processor has at least a MMU (virtual memory technically is an additional feature that's often built on MMU). If the CPU doesn't have a MMU, the virtual machine can perform some checks on the pointers (e.g. memory alignment if the CPU requires it). At my current level of sloppiness that's something that could be helpful if really I can't fix my bad habits.
> If you're having [segfaults because of] trivial function arity mismatch, you can't simultaneously believe that you're working in a higher level language on par with Common Lisp or Scheme, or even ANSI C.
I think I did say that Forth is indeed a low-level language. I have no problem with that, because "low-level language" doesn't mean "lesser language" to me.
Forth is indeed an assembly language for Forth processors, but Forth was never intended as some sort of intermediate language. It is a programming language for humans since 1970.
It's interesting to note that, unlike Lisp machines and other language-X-processors who are now rusting in museums, "Forth processors" are still being launched in space [1].
So, to anticipated about what you say later, it must be a cosmic buffoon. Better than dying from a slightly cold winter I guess.
> It's not a good VM for compiling dynamic languages
Off topic, but why would you do that anyway? At some point, register-based VMs outperformed stack-based VMs due to the evolution of processors (cache, branch prediction, large register banks) and progresses in compilation techniques.
Forth doesn't need to be "recycled" as a target language. It is useful enough for those who've practiced it long enough to understand its value proposition.
> Forth is completely forgiving, like an old buffoon. Pass four arguments to a three-argument function? All is forgiven.
Lua and Newlisp (and probably other Lisp variants) let you pass more arguments or less arguments to a function; you won't get any warning while the compiler/interpreter silently ignores the extra parameters or fills the missing parameters with nil.
In Forth there are some ways to detect argument mismatches, but really nobody cares about those training wheels. The problem is solved in a different way.
Also, many dynamic languages had to add a "strict mode" because letting people not declare identifiers is not so "user-friendly" after all...
I'll trade any day a language that breaks on stupid typos for a language that breaks because I forgot to push a result. Actually, that's why I did.
[1] https://en.wikipedia.org/wiki/RTX2010