Project

General

Profile

Actions

Feature #17398

open

SyntaxError in endless method

Added by zverok (Victor Shepelev) over 4 years ago. Updated about 6 hours ago.

Status:
Assigned
Assignee:
Target version:
-
[ruby-core:101475]

Description

This works:

def foo() = puts("bar")

This does not:

def foo() = puts "bar"
#                ^ syntax error, unexpected string literal, expecting `do' or '{' or '('

Is this intentional or accidental? Not sure how it is reasoned.


Files

Updated by mame (Yusuke Endoh) over 4 years ago

The body of an endless method must be an expression (called "arg" in the syntax rules of parse.y). puts("bar") is an expression, but puts "bar" is a statement (called "command" in the syntax rules).

I think it could be a bit confusing, but I have no idea whether we can/should allow a statement as a body of an endless method.

Updated by zverok (Victor Shepelev) over 4 years ago

@mame (Yusuke Endoh) Hmm, haven't thought about it from this perspective... Can you please explain a bit? As far as I can see, in, say, assignment context it behaves like an expression:

result = puts 'foo'
# prints "foo", result = nil

I am just trying to describe the behavior in full for the next installment of my changelog and this aspect is quite confusing for me... Though, it is not endless-method specific, as far as I can see:

y = sin x # OK
y = 1 + sin x
#           ^ unexpected local variable or method, expecting `do' or '{' or '('

What's the "rule of thumb" to understand this better?

Updated by Eregon (Benoit Daloze) over 4 years ago

Conceptually, according to the typical definition in computer science, both puts("bar") and puts "bar" are expressions (i.e., they return a value, and if it was some other method than puts it would also not always be nil).
It might be slightly less clear for e.g. a = 42 (it's still an expression, it still returns a value), but I think puts "bar" is clear that it should be the same as puts("bar"), except for precedence.

So it's probably going to be very difficult to explain the actual condition, other than showing specific examples.

Updated by austin (Austin Ziegler) over 4 years ago

Eregon (Benoit Daloze) wrote in #note-3:

So it's probably going to be very difficult to explain the actual condition, other than showing specific examples.

Endless methods definitions don’t support poetry mode?

Updated by mame (Yusuke Endoh) over 4 years ago

The following patch allows def foo() = puts "bar". It brings no parser conflict.

https://gist.github.com/mame/0773bf3938e046e2b608de5fb2a826c8

However, it is not perfect. private def foo() = puts "foo" does not parse.
private var = puts "bar" is not allowed neither, so I have no idea how to allow this.

Updated by matz (Yukihiro Matsumoto) over 4 years ago

  • Tracker changed from Bug to Feature
  • Backport deleted (2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN)

Pros

  • More intuitive / consistent / natural

Cons

  • Duplicated syntax rules
  • Even more complex syntax

If I were young, I would add @mame's patch. I did similar decisions many times in the past. But Ruby has been mature and complex, I now feel reluctant. Let us consider this idea for a while.

Matz.

Updated by matz (Yukihiro Matsumoto) over 4 years ago

I have considered this issue for a while and concluded it should be merged to be consistent with the assignment statement.

Matz.

Actions #9

Updated by mame (Yusuke Endoh) over 4 years ago

  • Status changed from Open to Closed

Applied in changeset git|31794d2e733e081e4e221f27aff6380393981681.


parse.y: Allow "command" syntax in endless method definition

This change allows def hello = puts "Hello" without parentheses.

Note that private def hello = puts "Hello" does not parse for
technical reason.

[Feature #17398]

Updated by yui-knk (Kaneko Yuichiro) 1 day ago

Note that private def hello = puts "Hello" does not parse for technical reason.

It's possible.
Patch is https://github.com/yui-knk/ruby/tree/bug_17398.
This change allows single endless method definition with command body as an argument of the method.
Some cases you might be aware are

  • private :m, def hello = puts "Hello"
    • This is SyntaxError because only single argument case is allowed.
    • This is same with one command is passed to argument. obj.m 0, cmd 1, 2 is SyntaxError.
  • private def hello = puts "Hello", "World"
    • This is interpreted as private def hello = puts("Hello", "World") not private (def hello = puts "Hello"), "World".
    • This is same with one command is passed to argument. obj.m cmd 1, 2 is interpreted as obj.m cmd(1, 2) not obj.m (cmd 1), 2.
  • private def hello = puts "Hello" do expr end
    • This is interpreted as private (def hello = puts "Hello") do expr end not private (def hello = puts "Hello" do expr end)
    • This is same with one command is passed to argument. obj.m cmd 1, 2 do expr end is interpreted as obj.m (cmd 1, 2) do expr end not obj.m (cmd 1, 2 do expr end)

Updated by mame (Yusuke Endoh) 1 day ago

  • Status changed from Closed to Open

Thanks, it looks good. @matz (Yukihiro Matsumoto) what do you think?

Updated by matz (Yukihiro Matsumoto) about 15 hours ago

Sounds reasonable, considering existing grammar.

Matz.

Updated by mame (Yusuke Endoh) about 15 hours ago

  • Status changed from Open to Assigned
  • Assignee set to prism

Ok, then we need a patch for prism

Updated by Earlopain (Earlopain _) about 6 hours ago

It is easy for prism to accept this as well: https://github.com/ruby/prism/pull/3632

I checked the above examples and prism seems to interpret them in the same way.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0