> Skipping parentheses is directly lifted from Ruby, because I really like it. Older versions took this further by also letting you write `function arg1 arg2`, but I got rid of that to make parsing easier. It's especially nice so you can do things like `if foo.bar.baz? { ... }` instead of `if foo().bar().baz?()`, though I suspect opinions will differ on this :)
I've spent a little bit of time in Ruby land and such cute syntactical tricks tend to have limited benefits (none?), but significant downsides.
This:
foo.bar()
communicates very clearly that arbitrary code will get executed now.
But:
foo.bar
could be arbitrary code execution or a trivial and cheap field access. No way to know which without extra information. Reading code like this stutters; every instance of x.y requires pausing to look up type information.
There's a second problem. Allowing:
foo.bar
but not:
foo.bar x y
applies special treatment to functions with zero arity. Is there a reason for that? As far as I know function arity carries no special significance.
Consistency shouldn't be disturbed without a sound justification.
There's one advantage of foo.bar calling a function, it works well with referential transparency. Whether it's a property/value or function, only the result matters. I can't say it's a big difference though, I've only been mildly annoyed by having to change all call-sites when changing between them. Other languages allow code bodies for getters/setters (foo.bar = ...) so it still hides the call. For a C-style syntax language having the () seems less surprising.
When it comes to correctness, only the result matters, sure. But not so for performance and code understandability. Obscuring points of arbitrary code execution is awful.
The getter/setter pattern is also bad, but a little less so since it's exceedingly rare any real code will get executed there.
I've spent a little bit of time in Ruby land and such cute syntactical tricks tend to have limited benefits (none?), but significant downsides.
This:
communicates very clearly that arbitrary code will get executed now.But:
could be arbitrary code execution or a trivial and cheap field access. No way to know which without extra information. Reading code like this stutters; every instance of x.y requires pausing to look up type information.There's a second problem. Allowing:
but not: applies special treatment to functions with zero arity. Is there a reason for that? As far as I know function arity carries no special significance.Consistency shouldn't be disturbed without a sound justification.