6 ms·
It's Forth tradition to make your own slightly incompatible Forth. Honouring that tradition, I suggest an extension to the VM. Either with a few registers, or
by retrac 5y ago
It's Forth tradition to make your own slightly incompatible Forth. Honouring that tradition, I suggest an extension to the VM. Either with a few registers, or a second stack. For pointers. That way, memory access to a single or handful of variables becomes a single word. Add things like dereference-and-increment load/store primitives and it becomes very C-like, and a rather nice target for compilers.
(I can't take credit for this idea: https://www.complang.tuwien.ac.at/anton/euroforth/ef08/papers/pelc.pdf https://www.complang.tuwien.ac.at/anton/euroforth/ef08/paper... "Updating the Forth Virtual Machine" by Stephen Pelc for EuroForth 2008, which is probably also not the first time someone suggested this.)
- kragen 5y agoInteresting! Some way to distinguish pointers from integers is kind of a sine qua non for memory safety; I've been kind of thinking along the lines of Smalltalk object descriptors, where each memory allocation is in a "segment" of its own, into which you can index with integers. That would save you from debugging segfaults. (But then, so does Hindley-Milner typing, and that doesn't cost a bounds-check on every memory access.) The part that so far puzzles me is how to do this without losing too much of Forth's simplicity. Pelc's proposal is to add scratch/index registers A and B (notably, not segregating integers from pointers) and base pointers X or LP (the frame pointer) and Y or UP (thread-local data pointer). His motivation seems to be primarily efficiency and clarity rather than memory-safety. Probably you want at least LP and UP to be callee-saved. If you make LP into an additional stack rather than just a register, then you save yourself a Y> >R on entry to subroutines that allocate stack frames, and half of a R> >Y on exit. (The CPU still has to do the same amount of work, but plausibly you spend less on op dispatch overhead and code space.) Doing the same with the A and B scratch/index registers might make sense, or you could just treat them as caller-saved. At some point restoring individual shallow-bound variables one by one stops being a good tradeoff, and it starts making more sense to put them in a stack frame or instance-variable vector and access them by indexing off a base pointer. Adding a small number of local-variable registers like this is kind of a pain for hand-programming, though, as opposed to as a compiler target. Instead of having to remember whether the quantity two levels down in the stack is the voltage or the current, you have to remember whether the A register is currently the voltage or the current. Much easier to say 0 VALUE VOLTAGE 0 VALUE CURRENT, or maybe VARIABLE V VARIABLE I, and then your code is always explicit about which one it's expecting. So I doubt Pelc's proposal can be justified on the grounds of clarity, rendering it merely a speed hack.
- astrobe_ 5y agoA strange game. The only winning move is not to play. If you want memory safety guarantees from the compiler, don't use Forth. The paradigm in Forth is "correct by design", "fail-fast" and to fight complexity unguibus et rostro. The paradigm in Forth is to increase the skills of the programmer rather than to increase the skills of the compiler. That's why it is a wonderful language for advanced training, IMO.
- kragen 5y agoThis is precisely the kind of self-aggrandizing macho nonsense I was criticizing in https://news.ycombinator.com/item?id=27159383 https://news.ycombinator.com/item?id=27159383. 1. What should you use if you want memory safety guarantees—whether because you're a novice, because you have better ways to spend your Saturday nights than disassembling core dumps, because you're building a platform for safely running untrusted code written by players who are competing against one another https://news.ycombinator.com/item?id=27160615 https://news.ycombinator.com/item?id=27160615, or because, given your own fallibility, you think it's the only way to be safe enough from ransomware gangs? Of course you're right that it's not ANS Forth or polyForth or machineForth, but what should it be? What's the lowest price in complexity we can get away with paying for that pearl? Surely we can do better than JavaScript. Or even PostScript. 2. You say the paradigm in Forth is "correct by design", "fail-fast" and to fight complexity uñas y rostro. Well, precisely what I want is to be fail-fast; standard Forth pointer arithmetic isn't, because indexing past the end of an array will just access some other object. That means that instead of failing fast it will usually produce incorrect results and possibly corrupt the data in that other object, producing errors downstream. To fail fast we need bounds-checking, and for bounds checking we need to distinguish pointers from integers. 3. You say, "The paradigm in Forth is to increase the skills of the programmer," which is to say, to be more difficult than necessary. You're free to make your Forth more difficult than necessary if you want, which is an enjoyable activity that will surely make you a better programmer, but that isn't what Forth was designed for. In fact it's close to the opposite of Forth's design principles, which are to fight complexity because complexity makes programming more difficult. That's why Forth programmers in the 01980s had IDEs with virtual memory, incremental recompilation, compile-time metaprogramming, reflection, and multithreading that fit on a floppy disk and could run in 64K of RAM. It's not because F-83 was written by superhumans; it's because Forth's design removed a lot of accidental complexity from the problems, allowing its implementors to focus on the essence. I mean, you're probably right that most people using Forth today are doing it, like Apollo, not because it is easy but because it is difficult. But that's not what Chuck Moore was looking for, it's not what Elizabeth Rather is looking for, and it's not what I'm looking for either.
- lebuffon 5y agoIndeed. Chuck Moore, the inventor, added the "A" register to his machine Forth for holding addresses and temporary values to reduce "stackrobatics".
- kragen 5y agoHe explained that this was in part due to hardware considerations. I don't really understand why, although unlike stack machines, I can speculate. But then he got to like it. He also eliminated all the stack operations from machineForth except DUP, DROP, and OVER. Not even SWAP!
- protomyth 5y agoPostScript has the ability to assign values to variables.
- kragen 5y agoCan you elaborate on how this relates?
- protomyth 5y agoA more general solution than Chuck Moore's A register but solving the same problem.
- kragen 5y agoHmm, I don't think assigning values to variables in PostScript with "def" is solving the same problem or even a related problem as the A register. Instead, it solves the same problem that assigning values to variables in Forth solves. As I understand it, the A register, introduced in the MuP21, solved some problems having to do with on-die fanout, fanin, and path length that limited the performance of the Novix NC4016 and the Harris RTX 2000. It also allows you to do operations like memset and memcpy without having to fetch and store the pointers to RAM (at fixed addresses!) for every byte/word read or written, which improves performance dramatically, makes the code a lot more readable (especially with its incrementing addressing modes), and makes the code more compact. None of these are problems that exist in the PostScript world. You can't use the A register in the MuP21 or F18A as a local variable, because it isn't local; it's shared with whatever subroutines you call and whatever subroutine called you. Moreover, the A register is the only way to read and write memory, so they can't avoid overwriting it if they need to read or write memory. [I've programmed in PostScript, and I've written a little Forth, but I've never programmed any of the chips mentioned above.]
- liberalbias998 5y agoMessing around with FORTH rather than writing apps using it is also a mental trap, at least at the hobbyist level.
- kragen 5y agoYeah, it's a common observation that more people have written their own Forth than have written useful programs in any Forth, whether their own or others'. Part of the reason is that Forth is a low-level language like C, which makes it easier to implement, and harder to write programs in, than, say, Python or Rust. But, although there are considerably more C compilers out there than Python implementations, C doesn't suffer from this to nearly the same extent. I'm no expert in Forth (though of course I've written a few quasi-Forths of my own) but I suspect that what's happening here is that, nowadays, the advantages of Forth over C or assembly just aren't great enough to counterbalance the disadvantages of using a minority language (like worse documentation, FFI, libraries, answers on Stack Overflow). Also, Forth compilers typically produce worse code than C compilers or assembly programmers, which rules it out for a lot of the applications where using a low-level language would be most tempting. That is, itself, a category that is smaller every year, in relative terms anyway. The difficulty gets made worse by the conceited bullshit discourse about how Forth programmers are an elite distinguished by their superior intelligence, a story I sometimes hear even from people who don't write Forth.