Why use a stack-oriented language?

8.3k views Asked by At

I recently took a look at Factor, and the idea of having a language based around the concept of a stack is very interesting. (This was my first encounter with a stack-oriented language.) However, I don't see any practical advantages of such a paradigm. To me, it just seems like more trouble than it's worth. Why would I use a stack-oriented language such as Factor or Forth?


I'm ignoring factors (excuse the pun) such as the availability of tools and libraries. I'm asking only about the language paradigm itself.

5

There are 5 answers

1
AshleyF On BEST ANSWER

Stack orientation is an implementation detail. For example, Joy can be implemented using rewriting - no stack. This is why some prefer to say "concatenative" or "compositional". With quotations and combinators you can code without thinking about the stack.

Expressing yourself with pure composition and without locals or named arguments is the key. It's extremely succinct with no syntactic overhead. Composition makes it very easy to factor out redundancy and to "algebraically" manipulate your code; boiling it down to its essence.

Once you've fallen in love with this point-free style you'll become annoyed by even the slightest composition syntax in other languages (even if just a dot). In concatenative languages, white space is the composition operator.

1
entropo On

For some people it's easier to think in terms of managing stacks than other paradigms. At the very least, doing some hacking in a stack-based language will improve your ability to manage stacks in general.

Aside: in the early days of handheld calculators, they used something called Reverse Polish notation, which is a very simple stack-based postfix notation, and is extremely memory efficient. People who learn to use it efficiently tend to prefer it over algebraic calculation.

1
Rupert Swarbrick On

I'm not sure whether this will quite answer your question, but you'll find that Factor describes itself as a concatenative language first and foremost. It just happens also to have a stack-based execution model. Unfortunately, I can't find Slava's blog post(? or maybe on the Factor Wiki?) talking about this.

The concatenative model basically means that you pass around "hunks of code" (well, that's how you program anyway) and composition looks like concatenation. Operations like currying are also easy to express in a stack-based language since you just pre-compose with code that adds one thing to the stack. In Factor, at least, this is expressed via a word called curry. This makes it much easier to do higher order programming, and mapping over sequences eventually becomes the "obvious way to do it". I came from Lisp and was amazed going back after programming in Factor for a bit that you couldn't do "obvious things" like bi in Lisp. It really does change how you express things.

Incidentally, it's wise not to get too hung up on the whole stack manipulation thing. Using the locals vocabulary (described here: http://docs.factorcode.org/content/article-locals.html), you don't have to worry about shuffling things around. Often there's a neat way to express things without local variables, but I tend to do that second.

0
Gabriel Cuvillier On

One of the important reasons stack-based languages are being developed is because the minimalism of their semantics allows straightforward interpreter and compiler implementation, as well as optimization.

So, one of the practical advantage of such paradigm is that it allows enthusiast people to easily build more complex things and paradigms on top of them.

The Scheme programming language is another example of that: minimalist syntax and semantics, straightforward implementation, and lots of fun!

2
olivecoder On

[EDITED] We already have good answers and I know nothing about the Factor language. However, the favouring of stack usage is a practical advantage of a stack-oriented paradigma and a reason to adopt such paradigma, as asked.

So, I think it is worth listing the advantages of stack usage instead of heap allocation for completeness:

  • CPU Time -- The time cost of memory allocation in the stack is practically free: doesn't matter if you are allocating one or one thousand integers, all it takes is a stack pointer decrement operation. example
  • Memory leak -- There are no memory leaks when using the stack only. That happens naturally without additional code overhead to deal with it. The memory used by a function is completely released when returning from each function even on exception handling or using longjmp (no referencing counting, garbage collection, etc).
  • Fragmentation -- Stacks also avoid memory fragmentation naturally. You can achieve zero fragmentation without any additional code to deal with this like an object pool or slab memory allocation.
  • Locality -- Data in stack favors the data locality, taking advantage of cache and avoiding page swaps.

Of course, it may be more complicated to implement, depending on your problem, but we shall favor stack over heap always we can in any language. Leave malloc/new to be used only when actually needed (size or lifetime requirements).