@sawa (Tsuyoshi Sawada) - My proposal would be to allow omitting parentheses only if there are no arguments provided, ie. how it is currently.
self.xyz = 6 # correct currently
self.xyz() = 6 # correct under the proposal
self.xyz(a) = 6 # correct under the proposal
self.xyz a = 6 # parser conflict, it is already a correct code meaning something else
I am not very familiar with MRI code unfortunately, so I can't estimate if this will introduce a lot of complexity or not. Certainly lvalue will need to accept a lot more types of expression. I develop an alternative Ruby implementation (Opal), though not its parser, and there I have a clear path for implementation of this feature.
A similar, though a little different, feature exists in C, where *get_mem(123) = 123
is a correct code.
Another argument for this feature is that it's easy to pass an arbitrary number of arguments to any operator, like +
, *
, []=
, []
, something?
, something!
. From what I know, something=
is the only kind of operator that needs __send__
to pass other number of arguments than 1 (self.x=(1,2,3)
is not a correct code, perhaps it could be an alternative to accept it, instead of this proposal, but I assume it will be a lot harder).
I happen to sometimes want to add an optional argument to setter and it ends up with a code refactor that makes code a lot more complicated, needing methods like set_x
, while I can easily add arguments to a getter.
@baweaver (Brandon Weaver)
The difficulty for such functions is how to differentiate between the varadic path and the value setter
While block adds a lot of flexibility for certain cases, like bury
, this proposal more clearly separates what's a variadic path and what's a value (following the semantics of []
and []=
operators). Perhaps my pseudo-code with dig=
isn't the greatest idea, but it demonstrates the concept.
A more real life example happened in my code. I wanted to create an API like the following:
entity.attribute(3) # => value of attribute 3
entity.attribute("attrtype 3 by name") # => value of attribute 3
entity.attribute(AttrType.new(3)) # => value of attribute 3
entity.attribute(3) = 10
entity.attribute("attrtype 3 by name") = 10
entity.attribute(AttrType.new(3)) = 10
Of course I ended up with extending Hash
to accurately resolve the hash keys. Instead of the API described above, I created this:
entity.attributes[3] # => value of attribute 3
entity.attributes["attrtype 3 by name"] # => value of attribute 3
entity.attributes[AttrType.new(3)] # => value of attribute 3
entity.attributes[3] = 10
entity.attributes["attrtype 3 by name"] = 10
entity.attributes[AttrType.new(3)] = 10
While I achieved the same goal by it, the resulting API implementation added a lot of complexity.