Issue #19392 has been updated by duerst (Martin Dürst).
Because `a = b and c` is interpreted as `(a = b) and
c`, it is natural that `def a = b and c` is interpreted as `(def a = b) and c`
I agree with others that there's not much (if anything) natural about this. In `def a
= b and c`, the most important thing that virtually every Ruby programmer will see is
`def`.
To formalize this, we can think about a special `def=` operator. This `def=` operator has
lower precedence than `and` or `if` or `unless`,... As a result, `def a = b and c` is
interpreted as `def a = (b and c)`, which is easier to understand and more useful (because
it is the more frequent usecase).
Parsing this so that `def=` has lower precedence may not exactly be easy. But the Ruby
parser goes through many contortions to make Ruby a language useful for human programmers,
with very little concern for 'parsing difficulty'.[1] It would be weird if we gave
up in this case because of 'parser difficulty'. `def=` has the huge advantage that
`def` is prefix, which is much easier to handle in parsers that an infix or postfix
operator.
[1] The opposite of this is Pascal and other languages created by Niklaus Wirth. Wirths
main goal when designing a language was to make the compiler easy to implement.
----------------------------------------
Bug #19392: Endless method and parsing priorities
https://bugs.ruby-lang.org/issues/19392#change-105604
* 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/