5 ms·
Something I like about this article is how it helps reveal what Forth's essence is: Forth is an extensible virtual machine Most interpreted languages that are
by kmill 6y ago
Something I like about this article is how it helps reveal what Forth's essence is:
Forth is an extensible virtual machine
Most interpreted languages that are implemented with a virtual machine (sometimes known as a bytecode interpreter) have a fixed set of instructions. Modulo some implementation details, writing new Forth words is akin to extending the virtual machine with new instructions.
However, the article's Forth is a more extensible form of this. The entire evaluation of the virtual machine is split into an extensible set of states (starting with only interpret, compile, head, forth, lit), new types of instructions can be introduced by adding to a list of heads (starting with only DOCOL and EXIT), and then words are, specifically, lists of addresses that the forth state interprets, whose evaluation is triggered by a DOCOL seen in the head state.
This opens up possibilities to define other sorts of interpreters for specific purposes. The article gives the example of polynomial evaluation, but you could also do something like have a variant of the forth state for token threaded code in memory-constrained environments. Sort of like how ARM has an additional Thumb instruction set.
More detail for this last idea: you'd have an array of, say, 256 pointers, and in the bforth state you'd read the next byte of the thread, look up the address in the table, push it on the RS, then go into the head state. This gives you perfect interoperability. You'd just need a special bcompiler state that would look up the bytecode for each word.
- MaxBarraclough 6y ago> an extensible virtual machine I've read similar ideas on Lisp. I don't put much stock in it in either context, but I think Lisp has a better claim to extensibility. All programming languages enable decomposition of a program. Functions/methods/macros/words don't really 'extend' a language. You can't easily add garbage collection to Forth. You can't easily add static type-checking to Forth. Why call it 'extensible'? It's no more extensible than C. It may be easier to hack on a Forth implementation than a C compiler, sure.
- kmill 6y agoAre you familiar with how to implement a bytecode virtual machine using a jump table? Forth is pretty much that, but the jump table is extensible. I meant it very literally. The fact that this is exposed inspires a certain way of programming, and this seems to be essential to the Forth way. This isn't saying too much about the language itself.
- frompdx 6y ago> Why call it 'extensible'? It's no more extensible than C. Extensibility refers to the ability to extend the compiler directly in the language. Lisp supports this with macros, which are not functions and are different than macros in C because they alter the behavior of the compiler, and Forth supports this with defining words and compiling words, which behave differently from other forth words because they alter the behavior of the compiler. Compare this to a macro in C, which pre-processes the macro into more C prior to compilation rather than at the time of compilation. In this respect, both Forth and Lisp are more extensible than C because facilities to extend the language exist within the language itself.
- MaxBarraclough 6y agoI think I follow, but it seems rather fuzzy. Compile-time functionality doesn't strike me as really extending the language. How about BOOST_SCOPE_EXIT in C++? [0] Is it extending the language, or just a trivial macro-based hack on RAII? What's the difference? My other issue with it is that the major features of programming languages that people actually care about, aren't the kinds of things you can implement with clever macros. They tend to rely on serious engineering. Even in a highly extensible language, you can't easily throw together features like industry-strength garbage collection, or a type system, or borrower-checking. (I considered listing formal verification but that would be unfair, it can't really be added to an existing language.) These things are implemented by compiler engineers, and always will be. (If I'm mistaken about that, and am underestimating anything, I'd be interested to know, but I don't think I am.) What's the 'killer example' of LISP macros? I can see a pretty neat example at [1]. [0] https://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/BOOST_SCOPE_EXIT.html https://www.boost.org/doc/libs/release/libs/scope_exit/doc/h... [1] https://docs.racket-lang.org/guide/pattern-macros.html#%28part._pattern-macro-example%29 https://docs.racket-lang.org/guide/pattern-macros.html#%28pa...
- kmill 6y agoYou can add garbage collection to Forth, but for the trivial reason that Forth is a low-level virtual machine to which you can add instructions/words for managed objects, and then you can add some words to help you interact with them more ergonomically -- words that run at compile time to change how code is being compiled. I don't think it's right to think of Forth as a "language" per se, although it's true there is a certain language that Forth programs tend to be written in, the one people call reverse-polish and concatenative. I can't say anything about adding a type system, because it's unclear what sort of type system would even apply here. But at least in Common Lisp (which incidentally already has a type system), I think the way you'd do it is create your own front-end that interprets and checks all the typing/borrowing information and then passes this to the usual compiler. There's a long tradition in Lisps to define interpreters that extend the base language in some way. SBCL even lets you hook into the compiler, and I saw some article about someone adding vectorization to SBCL using only user-level code. Regarding BOOST_SCOPE_EXIT, it's yes or no depending on what extending the language means to you. I think it's more useful to use a definition where the answer is 'yes.' It's true that C macros are not a very powerful interface for language extension, though. Also, it seems like you're saying that "extensible" means "easily extended" or "doesn't take serious engineering." It just means you can extend it (and, I'd add, in a principled way). Writing good Lisp macros can take serious engineering, but also there are other ways to extend Lisp. In Lisp, you can (and do) define pattern match destructuring and lvalue assignments entirely using macros. These are features that require a new edition of a language standard, usually.