4 ms·
Long, long ago I wrote a Forth of OS/2 out of spite. I've had a long standing interest in the language. It's been my opinion for a while that Forth is a less po
by mikewarot 1y ago
Long, long ago I wrote a Forth of OS/2 out of spite. I've had a long standing interest in the language. It's been my opinion for a while that Forth is a less powerful language than LISP, even though they initially appear to just be the opposites of each other in terms of argument handling.
The thing that makes Forth and other similar languages write-only is that you can easily lose track of the variables when you are forced to toss them all on a stack. When you add the ability to use local variables, you get some of that power back, but then you've added a huge impedance mismatch with the rest of the system.
As much as I hate all the () in Lisp, it's the source of much of its power.
- dreamcompiler 1y agoI write code in both and they seem pretty much equally powerful to me. There are two big differences for me: 1. If I look at Forth code I wrote a month ago I have no idea what it's doing. This is never a problem with Lisp. 2. I can -- and have -- written a complete Forth compiler bootstrapping my way up from assembler. Sounds like you've done the same thing. I could never bootstrap a Lisp compiler that way.
- geocar 1y ago> I write code in both ... > If I look at Forth code I wrote a month ago I have no idea what it's doing. Sometimes when we are learning a language, we plateau in our learning for so long we think we are done, however I assure you that other people can read Forth code written months or years ago, even written by other people, and can read it. That's not you, at least not yet, and you should be cautious with your certainty about things you just don't know about. Writing code is substantially easier than reading it, but reading is when it is possible for us to know the language. > I could never bootstrap a Lisp compiler that way. Don't be so hard on yourself: You can, but you would have to change and learn in order to do it.
- HelloNurse 1y agoLISP has more names (for function arguments), which convey more information.
- geocar 1y agoI don't think you know what you mean. Experienced Forth programmers do not tend to make functions with lots of stack-based temporary references, but leverage the hyperstatic nature of globals which are effectively keyword arguments for subroutines. Pre-CL, lisp programmers use dynamic variables in a similar way (especially around the reader and writer), and whilst this carried over into keywords in CL, the vestiges of the defaults being the old dynamic variables remains.
- HelloNurse 1y agoYou seem to be arguing that LISP can be written with more global variables and less function arguments than modern "mainstream" style, closely matching Forth with global variables: from the point of view of readability it means gratuitous handicapping by throwing away a syntactic advantage of LISP (actual, formal names instead of optional comments).
- geocar 1y ago> You seem to be arguing that LISP can be written with more global variables and less function arguments than modern "mainstream" style, closely matching Forth with global variables: I am not arguing anything of the sort. I am saying Forth programmers don't program Forth with deep stacks, and explaining how that is possible. > from the point of view of readability it means gratuitous handicapping by throwing away a syntactic advantage of LISP (actual, formal names instead of optional comments). I'm not sure exactly what you could possibly mean here. Sorry. standard-input seems like a perfectly cromulent name; I'm not sure how :stream is "more formal" or even what that means. Lots of lisp programmers I know prefer using a dynamic variable like standard-input instead of passing a keyword :stream argument, but friend if that's not you good for you buddy. I'm not trying to convince you one is better than the other for lisp, only if you've spent any time programming lisp you're surely familiar with this and so use it to have some idea how Forth programmers are able to program Forth without such deep stacks.
- vdupras 1y agoIt has to be something about familiarity, because for me it's the opposite. I find that nested parens in Lisp make the code pretty hard to read. It's difficult to pinpoint where the processing begins. I also find myself constantly scanning left and right for parens boundaries. It's exhausting. In Forth, you read your word from left to right, "playing" stack effect in your head, and you always know where you're at processing wise. Pretty simple, but I guess one must have inclinations towards thinking about the generated native code underneath rather than thinking in terms of symbols.
- deleted 1y ago[deleted]
- astrobe_ 1y ago> Forth and other similar languages write-only If you see write-only Forth programs, that's probably because they are poorly written, or maybe you are not familiar enough with Forth to read them. > is that you can easily lose track of the variables when you are forced to toss them all on a stack You don't "have" to keep everything on the stack in Forth any more that you "have" to allocate everything on the heap in C/C++. A Forth programmer who is not a dilettante will look for the data which is used throughout the program (e.g. a file or device handle, a memory address) and put it in a (global) variable. This eliminates most of the stack juggling and your definitions generally use no more than 2 arguments, so it's easy to tell what they do by looking at them.
- lucyjojo 1y agowell this paragraph pretty much guarantees that most of the forth code out there is write only.
- astrobe_ 1y agoYou realize you are talking about something you have never seen, right? I do. Maybe my ten thousand lines of Forth were barely readable. But not anymore. I have dozens of scripts meant to be throwaways, not something perfect and beautiful meant to published on Github, some of them I actually reused No Problem. And I'm not even a professional Forth programmer; it only has been my go-to language for scripts, prototypes, utilities for a solid decade now. Maybe your intuition tells you that it "has" to be write-only. Full disclosure: I became interested in this language because I thought there's no way it could be viable - forget about "write-only" and "readability", I was already over those fallacies at that time. But on the other hand, there was contrary evidence [1]. So I gave a honest and earnest shot at it. What I learned, among other things, is that most of the work is about going against the habits and ways of thinking that you learned from mainstream languages. Of course it is not something one can learn by stagnating in the comfort zone of Algol++ languages. [1] https://www.forth.com/resources/forth-apps/ https://www.forth.com/resources/forth-apps/
- lucyjojo 1y ago
- norir 1y agoThis is mostly a problem of concatenative language design. There is nothing preventing function definitions from having type signatures that are statically checked. In my concatenative language compilers, I always provide a function that causes the compiler to halt and print out all of they types on the stack at the call site during compilation as well as a runtime function that prints out the runtime values. I have found this to be quite effective for debugging. Because I don't support global variables, these functions give a complete view of ALL of the live values at any point in the program, which is quite hard in most languages. Local variables are also not necessary to have reasonable ergonomics, even in mathy contexts. Instead, the language can define special operators that access fields on the stack by type name and move or copy them to the top of the stack. For some reason, in the math example, the author deliberately added an unnecessary parameter that had to be dropped and put the arguments in the wrong order. Cleaning up the signature, there are several reasonable ways to solve the problem in a concatenative language with the features I've described. type n number type y n type x n def op_math_example [(y x) -> (n)] \\x * \\y \\y * + \y abs - where \FOO moves a value of type FOO to the top of the stack and \\FOO copies the value to the top, leaving the original where it was. Yes, the \\ is a little ugly, but these should generally be used sparingly. Even if we restore the original signature and use the author's syntax, there is a much cleaner solution to the problem without the move/copy operators. def sq dup * def op_math_full drop swap sq over sq + swap abs - This is extremely cryptic. I suspect most forth programmers would have added a stack signature comment, but it is even better if the compiler statically verifies the signature for us, which is how the language I am describing differs from vanilla forth (where stack comments also have the risk of being wrong in an evolving system). If we restore the type system, it becomes: type n number type x n type y n type z n def sq [(n) -> (n)] dup * def op_math_impl [(y x) (n)] sq over sq + swap abs - def op_math_full [(x y z) -> (n)] drop swap op_math_impl Of course it is still not as obvious to the reader what op_math_full actually does as (y * y) + (x * x) - abs(y). But in practice it would have some name like projection_size so once it has been written correctly, it doesn't really matter that it is a bit obscure to read at a glance. You also get really good at simulating the stack in your head and they type signature makes this much easier. Still, when you are confused, you can always add stack debugging like so: def projection_size [(x y z) -> (n)] drop swap PRINT_STACK sq over sq + swap abs - 1 2 3 projection_size and the output would be something like: ({ y 2 } { x 1 }) Writing programs in this style is very nice so long as you have enough tooling to facilitate it. I have only used concatenative languages that I have implemented myself, however. I have read quite a bit about forth, but for me, there are clear problems with vanilla forth that are solved for me with the meta operators like [, [[, \ and \\ as well as good debug tools like PRINT_STACK above. Forth was an incredible discovery for its time. We can do a lot better now.