>Lispers: prefix notation is superior
<Forthers: postfix notation is superior
I say the omnifix notation is superior. The omnifix function call syntax allows the arguments to be placed for OR after the function. It is an extension of the UFCS or method call syntax that is present in Nim, D, and possibly other languages.
What is UFCS? In C-style languages where the dot operator is typically used as the property access operator for objects, structs, or any other dictionary-like data structure, the dot operator is given the additional role of transforming syntax as follows:
//The following are equivalent
f(a);
a.f();
a.f; // empty parens optionally dropped
//The following are equivalent
f(a, b, c);
a.f(b, c);
Thus, it allows a function written outside a class (or if the language doesn't have classes) to be used as if it were a "method" of an object. Here's what it looks like in imaginary curly-brace language:
// declare a type O to be an object that has a property p of type P
typedef O =
object {
p: P
};
// when you make this declaration, it's like there is implicity declared a getter:
func __get_O_p(o: O): P;
// and a setter:
func __set_O_p(o: O, p: P): void;
//so...
o.p;
//is equivalent to
__get_O_p(o);
//and...
o.p = p2;
//is equivalent to
__set_O_p(O, p2);
This syntax is present in several languages. But what if it were extended to handle more than one argument, so that the following is true:
f(a, b, c, d)
== a.f(b, c, d)
== b.a.f(c, d)
== c.b.a.f(d)
== d.c.b.a.f()
== d.c.b.a.f; // empty parens optionally dropped
Now you can have prefix AND postfix, together in one unified syntax. And you don't need class keywords.
It also works with named arguments.
func f(a: int, b: int, c: int): int {
(a + b) * c;
}
// Prefixedly:
f(1, 2, 3); // == 9;
f(c = 3, a = 1, b = 2); // == 9;
// Postfixedly:
3.2.1.f; // == 9;
// Omnifixedly
3.1.f(b = 2); // == 9;
3.f(b = 2, a = 1); // == 9;