8 ms·
Stem, a stack-based language with metaprogramming and a C FLI
- ret2pop 3y agoreally cool project! (I am definitely not the person who made this)
- SrslyJosh 3y agoThis seems like a great introduction to stack-based languages! I'm curious, why did you undertake the project? What are your goals for it, or what problems do you intend for it to solve? I'm going to include a bit from the README here, which describes some of the functionality/design but not the why behind the language: > Stem aims to be a minimal interpreted stack based programming language that allows for metaprogramming and a foreign language interface. It features a C API that is elegant and simple. Additionally, garbage collection is not needed in this language as the responsibility of writing memory safe operations is put in the hands of the maintainers of the builtin functions and FLI library maintainers. Therefore, the end user does not need to worry about memory allocation while the implementation remains extremely simple. Ref: https://github.com/ret2pop/stem https://github.com/ret2pop/stem
- deleted 3y ago[deleted]
- ret2pop 3y agoI decided to undertake the project after my friend Matthew Hinton introduced me to stack based programming -- he claimed that they were elegant because they allowed for both easy metaprogramming and side effects, to which I agreed after writing a little bit of my own language. It was really easy to implement, too -- most of it took only one day, and getting the basic functionality working took only 2-3 days. Goals -- I eventually want to write an emacs-like text editor in stem by writing a C library that does bindings for ncurses. I think it would be fun, for one, and I think it would not be that hard of an end product to make. I also had plans of writing a stem compiler, and I already pretty much know how to do that, but there are a couple of difficulties in doing that. Namely, right now, there is no way of telling the difference between compile-time and runtime operations, which will slow the language down considerably. My solution to this currently is basically "interpret once, run binary forever", but the details are still need to be worked out. Problems it solves -- to be honest, you can really do anything in any programming language, but this langauge aims to be a higher level rendition of stack based programming languages, mostly for scripting and creating abstract representations of things. Note that I am still trying to write in a couple things, namely, an actual include statement as a builtin that reads from some predetermined standard include directory, and an OOP implementation using metaprogramming in the standard library. Not to mention the fact that I have been really interested in writing programming languages since I was in high school. One interesting thing about stack based languages is that the AST need not be generated at all. I taught myself a lot of linguistics, specifically generative grammar, as a result of attempting writing various programming languages in the past, and so these types of projects are just interesting to me. If you ARE looking for one unique thing about this language, though, it is that `def`, the method by which you define functions, is itself a word. I don't think a lot of stack based languages do this (because it is much harder to compile languages like this as mentioned above), but it offers much more internal consistency within the language as a result.
- transfire 3y ago> `def` … is itself a word. But of course, that is the way of the Forth. Hmmm… Have a look at JonesForth. I think it might be very rewarding for you.
- ret2pop 3y agocorrect me if I am wrong, but from my knowledge concatenative programming often assumes a different syntax for defining words. Usually it looks something like : add a b + ; if I am not mistaken.
- klyrs 3y agoThat isn't syntax. : is a word, and so is ; Cool article posted to HN a little while back: http://ratfactor.com/forth/the_programming_language_that_writes_itself.html http://ratfactor.com/forth/the_programming_language_that_wri...
- ret2pop 3y agoI was not aware of this, thanks for giving me an explanation. I don't have any experience writing in forth, my friend described this type of language to me and I implemented it.
- klyrs 3y agoYour language is really neat, thanks for putting it out there
- ret2pop 3y agoHey thanks! I didn't think people would actually care about this lol
- crq-yml 3y agoYou should go implement the FORTH-83 wordlist. (arbitrary pick, but it's easy to find documentation for the words) Doing that will reveal exactly how powerful and succinct Forth has always been, because the compilation/execution distinction in Forth is just a bitflip.
- FwarkALark 3y ago> This seems like a great introduction to stack-based languages! Do you know of a language which is not based on stacks?
- throwaway17_17 3y agoIn this case, ‘stack-based language’ is used as a term of art. In particular, in programming language discourse the typical meaning of ‘stack-based’ is a language which there’s a stack threaded through successive procedure calls, where access to the values on that stack are accessed by popping them off and computing with them, then returning a result via a push. The stack is implicit and there are often no mechanisms to name values or to name particular locations on the stack, requiring all procedures to explicitly shuffle, rotate, pop, and push the stack to access data for computation. I would say that languages where values are assigned a ‘name’ in the program text are not ‘stack-based’ in the manner implied by the term. So while C and nearly all other programming language have a stack data structure allocated as storage for values used in procedures/functions, they are not ‘stack-based’.
- FwarkALark 3y ago> In this case, ‘stack-based language’ is used as a term of art. This is a shitty and broken term. Hence my comment. > is a language which there’s a stack threaded through successive procedure calls, where access to the values on that stack are accessed by popping them off and computing with them, then returning a result via a push. You're just describing a procedural language that returns values. I suppose you could also describe a procedural language that doesn't return but what would be the point? You're just describing a form of indirect subroutines that revolve around jumps rather than the natural instruction progression. This has been a wildly unpopular method outside of entering a performance loop for many decades. It knows it will never have to exit/unwind the stack/call any kind of destructor or deallocation callback when entering a non-exiting loop. Ok so why don't people (you!) just say "concatenative" given that other languages are trivially stack-based as well? How is it surprising at all that it's mostly syntax and a mediocre runtime (as the majority of languages can boast) that differentiates your pet language from other languages? Can we just admit that one of these options has a complex syntax and the other has a trivial syntax?
- dcreager 3y agoThis is very cool, well done! I love seeing people get interested in other programming paradigms, like concatenative languages. I gave a talk about them at Strange Loop / PWL last year: https://dcreager.net/talks/concatenative-languages/ https://dcreager.net/talks/concatenative-languages/
- brezelgoring 3y agoI have no comments on the project itself, which I’m sure is very nice. If you’re taking suggestions, the mobile web view unfortunately captures 75% of the viewport on the side menu, it’d be nice if it were collapsible or flexible. Keep on keeping on!
- deleted 3y ago[deleted]
- ret2pop 3y agoYes. I have realized this. I added a meta tag to the website recently, I don't know if that solves the problem. I don't know much about css really. Edit: temporary fix of simply hiding the sidebar. lol.
- msla 3y agoWhat's the difference between an FLI and an FFI?
- ret2pop 3y agoI'm kind of just using words. You can call it whatever you want, I just used words that my friends also used to describe what I wrote. Really, loading custom libraries from C is really easy but I decided to advertise that part of the project anyway.
- ithkuil 3y agoI have a related question: is there a different terminology for when you can call an arbitrary C function versus when you need to implement a C function with a special signature (which often can be used to bridge the target C function) ?
- kazinator 3y agoIf you have to implement C code and load it, you're making "extensions", "plugins", "(low-level) modules", ... it is not FFI.
- FwarkALark 3y agoNothing.
- spindle 3y agoSome other stack languages (not all of these concatenative languages use a single stack but most of them do): https://concatenative.org/wiki/view/Concatenative%20language https://concatenative.org/wiki/view/Concatenative%20language
- FwarkALark 3y agoIs there a language which is not stack-based? I imagine "concatenative" would be mildly more precise of a description. Coroutines (which often carry their own stacks) can sort-of dodge stacks—effectively utilizing a sort of bespoke linear typing to avoid this—but I don't know of a language which doesn't have c-like, stack-based procedures or subroutines, which places arguments on the stack and registers and operates mostly with respect to that stack and foreign API calls. A stack is certainly the most intuitive data-structure with which to implement a lambda calculus. Really, what Forth and descendent languages seem to emphasize is a sort of a data-oriented execution rather than a symbol-oriented execution—C very much encourages you to name types, function signatures, etc, and the result if you don't is extremely difficult to parse and interpret manually, even if you can implement forth as a subset of C. Forth emphasizes reasoning about the stack directly as data, seemingly forgoing any assistance outside of syntax. Arguably it forgoes the utility of syntax, too.
- ret2pop 3y agoYes, you are correct. My friend made this post so I didn't have control over the exact wording. That being said, in concatenative programming, the stack is public and, in my case, is virtual.
- pizza 3y agoTrue, it's a convenient structure, but the Church–Rosser theorem says that the order of beta reduction of terms in the lambda calculus doesn't matter, so a call stack pattern isn't essential.
- deleted 3y ago[deleted]
- jkafjanvnfaf 3y agoFor completeness, there are languages that do not require stacks to implement (nor any workarounds that in practice emulate a stack). If you do not support explicit recursion, you don't need one. All variables can be statically allocated and only a single return address needs to be stored for each function, so you do not need a stack for return addresses either. The most famous example is FORTRAN, until 1990 when they added RECURSIVE directive.
- transfire 3y agoA similar language that’s been worked on for a while now is [Min](https://min-lang.org/ https://min-lang.org/). Interestingly it is written in Nim. I was interested in the C interface part but it never got there. :(
- ret2pop 3y agoWriting that part right now
- ret2pop 3y agoI've updated the blog to include a short explanation of it.
- h3rald 3y agomin creator here :) min does not have a C FLI essentially because it has a "Nim FLI". It is really easy to add new symbols to the language using a Nim API (which is also used internally to define all symbols of the language). See https://min-lang.org/learn-extending/ https://min-lang.org/learn-extending/ for more info. Maybe I should generate some Nim docs for the public API though... but it's really easy to use, and you can check the lib folder of the repo for examples: https://github.com/h3rald/min/tree/master/minpkg/lib https://github.com/h3rald/min/tree/master/minpkg/lib
- travisgriggs 3y agoI think it’s cute/ironic that the first word the document introduces you to is “.” Which in normal English is something we used to separate runs of words.
- mananaysiempre 3y agoStandard word for printing the topmost element in Forth for decades, though. (The 1970 manual[1] uses it to introduce definitions instead, in place of the modern-day colon, but by 1977 using it for printing was already the consensus and made it into the Forth-77 standard[2].) It is less than perfect for programmatic use, what with the obligatory space afterwards and no field-width support (there are other words for that), but very nice in a REPL, where using a single unshifted key on a US keyboard is important[3]. [1] https://www.1strecon.org/downloads/Forth_Resources/CM_ForthLanguageInteractiveComputing_1970.pdf https://www.1strecon.org/downloads/Forth_Resources/CM_ForthL... [2] https://www.complang.tuwien.ac.at/forth/forth-77.txt https://www.complang.tuwien.ac.at/forth/forth-77.txt [3] http://yosefk.com/blog/i-cant-believe-im-praising-tcl.html http://yosefk.com/blog/i-cant-believe-im-praising-tcl.html
- astrobe_ 3y agoI've wondered for a long time why the dot was chosen for this instead of the question mark. Using the dot instead of the the semicolon to end definitions seems more natural (as far as "natural" makes sense in an RPN language). That's what I did in my dialect. I understood why when I wanted to use it as a calculator. All relevant keys for simple computations are then on the keypad. Well, Forth is flexible enough that you could define "00" to display results; the rule is that the interpreter looks for tokens in the dictionary first, and the try to convert to a number if a word of that name doesn't exist.
- James_K 3y agoI've never really understood stack based languages. Getting rid of variables only seems make things harder, and you always inevitably need some kind of control flow that isn't stack based (for instance the pair "[" and "]"). In this case, I suppose the advantage is that the stack is shared with C so it's easier to interact over FFI. From what I've seen of other forths, I much prefer how this one does things. Using quoting as a sort of lambda is much nicer and more consistent than the weird compilation semantics you see in stuff like GForth.
- mananaysiempre 3y agoForth-likes are very very simple to bootstrap in basically any environment (contributing to their popularity back in the age of microcomputers sold with no OS), and once you’ve accepted the syntax are perhaps the most lightweight environments for doing DSLs (which is somewhat related, as one of the typical bootstrapping paths has you writing an assembler DSL as one of the first steps). The “postfix Lisp” PostScript/Joy/Factor heritage that TFA’s language belongs to inherits the latter property. If I had a choice of making and then using a DSL in Python, Lua, or Forth, it’s Forth all the way, no question. Now if you include Scheme, Ruby, or Tcl, then it might become a competition. (Haskell is somewhere in between.) It’s worth appreciating how much above his weight the humble granddaddy is punching here for the dozen K of memory that a running system normally takes. (Less relevant now than for the micros of old, as for interactivity that memory needs to be RAM, whereas the cheapest controllers today are usually ROM-rich and RAM-starved, relatively speaking.)
- astrobe_ 3y agoThis [] pair for quotations is pretty common in "modern" concatenative languages. But you actually don't need them that much, at least in Forth. It is not a solution because they have misidentified the problem (due to lack of experience, generally), or created a problem ex nihilo by trying to one-up Forth on RPN purity and do control-flow like Smalltalk does. a priori "must haves" that eventually get in your way. If I had to choose one quote from Chuck Moore (the creator of Forth), it would be "Don't anticipate, solve the problem you've got" [1]. What you need on a daily basis it to be able to reuse names so that you don't clutter your dictionary. But at the same time you do want your Forth to warn you when you define twice the same name, because that could lead to vicious bugs. So all you need to do is to hack your Forth so that e.g. names starting with underscores can be redefined and won't trigger a warning. [1] https://www.ultratechnology.com/1xforth.htm https://www.ultratechnology.com/1xforth.htm
- ColonelPhantom 3y agoAre there any practical and somewhat popular stack-based/concatenative languages? 'Popular' here doesn't need to mean that popular, something on a similar usage level to some Lisp dialects, or functional languages like Haskell.
- ret2pop 3y agofactor seems to be doing pretty well, and so is of course forth.
- mananaysiempre 3y agoHaven’t checked up on Factor in quite a while—have others picked up the work after Pestov was spirited away to Apple and locked in a room with nothing except Swift? That’s some good news if so.