However, I'd say for practical purposes, it still leaves me with the problem that in my day to day coding I'm left with the same ambiguity. I don't know if I'm calling a simple-assignment auto-generated method that is setting a property, or a method that does all sorts of stuff under the hood.
While I'm still fond of Ruby, I've come to prefer less ambiguity. I like to be able to see at the calling site whether what I'm doing is calling a method or setting a property, and parentheses are a great way to signal that.
As an aside, one thing I didn't like about Elixir was that it also made parentheses optional. Once I realized why this was necessary, and once the formatter was added and enforced parentheses as a default, it stopped being a problem. Still, every language I've used where they're optional have caused weird little problems that never seemed to be outweighed by the convenience (CoffeeScript comes to mind).
But all that said, it's not too high on my list of things to hate on :).
Ocaml does something similar. If you have nested function calls in a line of code, the interior calls look just like lisp. But the outermost one omits the parentheses.
In Ruby, as is also true in many languages that have a syntactic distinction, setting a property is always ultimately calling a method, so the distinction is illusory. What you may want is a purity guarantee (well, that getters are pure and than setters have no effects except on the state specifically backing the property, but the latter gets complicated to apply to nontrivial properties), but most languages that let you distinguish whether properties or methods are exposed in an API don't provide a that kind of guarantee with properties, either, just more boilerplate code to implement them.
And the whole point of properties over exposed data members is to abstract behavior so that implementation changes don't change APIs.
What you're describing holds in e.g. Scala, where it's by design: they feel it should be an easy-to-change implementation detail whether a name is backed by a direct field access or a method. IMO that's a reasonable stance in a functional(ish) world.
“Properties”, in most languages that have them, are an way to make method access look like access to data members (no parens, getters just use the name, setters use name + = with the new value on the right of the = instead of in parameter position.)
https://en.m.wikipedia.org/wiki/Uniform_access_principle
it takes some getting used to, but it’s now one of my favourite things about Ruby.
You seem to confusing “properties” with “data members” which, it is true, Ruby does not permit external access to except via method calls. But properties are a way of calling methods with a syntax that looks like direct member access, not actual direct member access.
I think this is a rather elegant solution to properties, that you always need to expose them with getters and setters and that properties and methods do not share the same namespace.
Scala has similar conventions, I believe.