The natural implementations are different:
- Postfix ordering requires a stack of only values, where operators are applied immediately, taking their operands off the stack. The execution loop for an interpreter is straightforward: read the next instruction from the program, and evaluate it.
- Prefix ordering requires a stack which can contain both operators and values. An operator like
add
is pushed to the stack, and not evaluated until there are sufficiently many operands on the stack above it. The execution loop for an interpreter is different: read the next instruction from the program and push it to the stack; then while the top-most operator on the stack is followed by sufficiently many values for its operands, evaluate that operator.
This ignores how the implementation evaluates quotes, but that is covered in this other question.
It seems to me that the implementation is much simpler using postfix ordering, and this will be decisive for concatenative languages which aren't meant to be written by humans (e.g. PostScript).
There is also a semantic difference which favours postfix notation: in prefix notation, each operator must take a fixed number of operands, in order to determine when the operator should be evaluated. On the other hand, postfix notation allows an operator to accept a variable number of operands, e.g. by consuming the whole of the stack.
As discussed in the comments, either of these implementations could be used for either prefix or postfix order ─ you can just reverse the program's tokens to switch the ordering. However, this would give a language where the side-effects of instructions are evaluated in the opposite order to which those instructions are written. This seems undesirable to me, but in principle a language could be designed this way.
Alternatively, the language could be designed in such a way that instructions don't have side-effects, and instead a program's output is simply a value left on the stack when it terminates. Or for interactive programs, perhaps something like Haskell's IO
monad could be used, so that the order that terms are evaluated in doesn't have to be the same as the order their side-effects are observed in.
So other implementations than the above two are possible, but I'll focus on these because they're straightforward, and have the desirable property that the program's side-effects are evaluated from left to right.
For concatenative languages meant to be written by humans, the ease of language implementation may no longer be the deciding factor.
The main ergonomic difference between these two approaches is what you already identified: the syntax places functions before their arguments, which is closer to how humans think about programming. A similar issue is that a variable name can precede its initialiser, which particularly matters when the initialiser is a long expression. Here's an example using my own toy concatenative language, fffff:
(
n 3 % 0 = >three
n 5 % 0 = >five
("fizz" print) three if
("buzz" print) five if
(n print) three five or not if
"" println
) >!print_num
This snippet declares a quote (i.e. a user-defined function) and binds it to the name print_num
─ but the name doesn't appear until after the end of the quote. This is a significant readability issue. With prefix notation instead, the name would appear at the start, which would be more sensible.
Another ergonomic issue is in debugging. If the program is paused during execution (e.g. due to a runtime error, or hitting a breakpoint), the programmer will be able to observe the current program state. As discussed above, prefix order and postfix order have natural implementations in which the program state would be a stack of operators and values, vs. a stack of just values, respectively. It's difficult to say which of these is more useful for debugging purposes, but a stack containing operators might be preferable since it more closely resembles a stack trace in an imperative or functional language, and may give better context about what the program was doing when it was paused.