Issue #19392 has been updated by zverok (Victor Shepelev).
@mame I understand I might sound annoying, but I believe there is **absolutely nothing
natural** about this behavior for the users (as is shown by the confusion of _everybody_
who is met with this behavior in real codebases: it is frequently impossible even to guess
where the problem is coming from).
While we reused `=` sign to designate one-line methods, it is _not_ "like any other
assignment":
1. It doesn't assign a value, actually, that can be then operated by value rules;
2. It can't be used in method bodies (or, it can, but the result wouldn't follow
the logic of other assignments, but follow the logic of method definitions, affecting the
outer scope);
3. It doesn't evaluate the expression on the right but "stores" it as a
method body.
The expectation of _every_ sane usage of endless methods is that "I have a short and
expressive method body, I want to put it in one line, it should just work," i.e.,
that whatever it would be:
```ruby
def foo(args)
expression
end
```
and
```ruby
def foo(args) = expression
```
would be equivalent in as many situations as possible.
While some "this can't be parsed at all" situations might be accepted,
"it is parsed successfully, but the scope changes in the middle of what looks like a
single expression" would never ever be "natural."
The most annoying and confusing thing is "trailing `if`" because it is an
incredibly widespread statement for short-and-expressive code.
I understand the complexity of the parser development (and I can even assume that fixing
the problem is downright impossible, though I hope it is not so).
Still, I believe that with current behavior being preserved, **the feature would be
forever considered "buggy and undercooked" and will never see wide adoption**,
indirectly affecting the reputation of the language.
**Can we please have one more round of discussion, even if after 3.3 release?**
I am ready to try to contribute as much as possible, from preparing a presentation to give
at the developer meeting with more detailed argumentation to trying to look at the parser
myself. Unfortunately, I am not proficient in this part of Ruby code, but I can try;
though, to invest a significant amount of time into this attempt, I would like to at least
have an agreement on the fact that if the fix is possible, it would be considered.
----------------------------------------
Bug #19392: Endless method and parsing priorities
https://bugs.ruby-lang.org/issues/19392#change-105577
* Author: zverok (Victor Shepelev)
* Status: Closed
* Priority: Normal
* Backport: 2.7: DONTNEED, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN
----------------------------------------
**Initial description**
[
Discovered](https://twitter.com/lucianghinda/status/1617783952353406977) by Lucian
Ghinda:
```ruby
def test = puts("foo") and puts("bar")
# prints "bar" immediately
test
# prints "foo"
```
It seems that it is a parser error, right?..
```ruby
RubyVM::AbstractSyntaxTree.parse('def test = puts("foo") and
puts("bar")')
# =>
# (SCOPE@1:0-1:38
# tbl: []
# args: nil
# body:
# (AND@1:0-1:38
# (DEFN@1:0-1:22
# mid: :test
# body:
# (SCOPE@1:0-1:22
# tbl: []
# args:
# (ARGS@1:0-1:8 pre_num: 0 pre_init: nil opt: nil first_post: nil post_num: 0
post_init: nil rest: nil kw: nil kwrest: nil block: nil)
# body: (FCALL@1:11-1:22 :puts (LIST@1:16-1:21 (STR@1:16-1:21 "foo")
nil))))
# (FCALL@1:27-1:38 :puts (LIST@1:32-1:37 (STR@1:32-1:37 "bar") nil))))
```
E.g. it is parsed as
```ruby
(def test = puts("foo")) and (puts("bar"))
```
...which is hardly intentional or have any practical use. The rightly parsed code in this
case _can_ have practical use, like
```ruby
def write(data) = File.write(@filename, data) == data.size or raise "Something went
wrong"
```
**Additional cases of what seems to be the same problem**
```ruby
def save = File.write(name, self.to_yaml) unless invalid?
# Parsed as:
(def save = File.write(name, self.to_yaml)) unless invalid?
```
...which makes it very hard for the users to diagnose the real reason, see #19731
```ruby
def initialize(a, b) = @a, b = a, b
# syntax error, unexpected ',', expecting end-of-input (SyntaxError)
# def initialize(a, b) = @a, b = a, b
# ^
# Again, parsed as
(def initialize(a, b) = @a), b = a, b
```
While this one is at least diagnosed early, in pathological cases, it might lead to very
subtle bugs:
```ruby
private def start = @operation, @conversion = :print, :to_s
```
This code doesn't throw a syntax error, but its effect is very far from expected.
Again, it is parsed as
```ruby
private( (def start = @operation), @conversion = :print, :to_s )
```
...and ends up in:
* defining a private method `start`
* making private methods `:print` and `:to_s`
--
https://bugs.ruby-lang.org/