There’s a pretty simple reason for that: autocomplete.
In most halfway decent dev environments, typing “object.” will present you with a list of possible operations on that object. OTOH, if you want to do “method(object)” you need to know the method name (in all current scopes, including globals).
I’m not saying this is the only or even best way to write code, but it’s definitely a factor IMHO.
result foo(bar b, other stuff)
result foo(baz b, other stuff)
result foo(bum b, other stuff)
To: result r = bar.foo(other stuff)
result r = baz.foo(other stuff)
result r = bum.foo(other stuff)
Not because of the IDE, but because the compiler error messages are horrible for the ones above when you make a mistake. If you pass the type as the first argument, the compiler "helpfully" tells you 3 pages of information about all of the overloads. However, if you use method syntax, it only tells you overloads for the one object.It's a little frustrating that the hammer is changing the shape of our hands, and not vice versa.
The problem I have with most language's function call syntax (except for point-free stack based languages like FORTH and PostScript) is that you can have multiple fingers on your "in" hand, but only one finger on your "out" hand. C#'s in/out/ref modifiers and Lisp's multiple-value-bind are hacks.
https://en.wikipedia.org/wiki/Tacit_programming
FORTH's /MOD ( numerator denominator -- remainder quotient ) naturally takes two integer inputs and returns two integer outputs, and it doesn't use need any special clumsy syntax to express that.
I dunno, in many modern languages that aren't point-free stack-based languages you can (and the difference between these is one of perspective more than concrete substance, arguably) either have multiple “fingers” on either hand or only one on each, but the one value each touches can be arbitrarily structured and destructured.
I think Python's way isn't amazing, but it's not too bad either:
d, r = divmod(100, 3)
It's a bit uglier in C++, but you could make this work: int d, r;
refs(d, r) = divmod(100, 3);
I'm certain there's either a Boost or STL library for this. (I wrote my own for C++98 at one point)It's clear you like stack based languages, and I certainly admit they can be concise.
the "hammer" in this case being "doing things in causal order" - hard to find a different tool in the shed.
A._vtable[f](A, B)
It really is just a function of two arguments, even when the privileged first argument looks like it's outside of the parens.However, I think using methods to provide infix syntax is a real mistake. For instance, if I want to make an infix operator which allows me to subtract mytype and yourtype, I can do the following:
mytype - yourtype; // mytype.sub(yourtype)
However, the opposite requires me to add methods to yourtype: yourtype - mytype; // yourtype.sub(mytype)
Python gets around this by having 'r' versions of functions which get invoked if yourtype refuses to acknowledge my type. However Go and Rust could resolve which binary function to use statically, but they don't want to support overloading unless it's a method on the first object.