[ruby-talk:444316] Multiple statements inside ()

Hello, Is () supposed to allow multiple statements in it? Documentation is not explicit about it. https://docs.ruby-lang.org/en/master/syntax/control_expressions_rdoc.html#la... E.g. puts((:ignore; :x)) # x puts (:ignore; :x) # Otoh, raises an unexpected semicolon error I'm looking at using () in a while loop's condition but please just consider that as an extra info. I need an official answer on my query above. -- konsolebox

Yes, when () is meant to yield a expression, you can put several statements in it. For example, consider: (x = Module.new; p x)::C = 1 the first segment in a constant reference like that is an expression. Normally, that expression is a simple constant reference, as in A::C = 1, or a variable, as in a::C = 1, in which case parentheses are not needed. But if you use parentheses, the expression in turn can be composed of multiple statements. As with return values in methods, the value of the ()-expression is the value of the last internal expression. In the example above, we have a first expression, which is an assigment: x = Module.new Its value is discarded, but x now stores a value. After it, there is a semicolon (could be a newline too), so Ruby continues execution and finds p x that method call prints the module object stored in x (say, #<Module:0x0000000107787b40>), and returns x. Since x is what the last expression evaluates to, that is what the whole () evaluates to, a module object. With that module object, Ruby moves forward and assigns C into said module. Now, parentheses have different meanings in different places. For example, if you do this enum.each do |(a, b)| ... end (a, b) does not play the role of an expression, right? Similarly, in your examples with puts, puts(...) is parsed as puts + the argument list of the call. Again, not an expression. In an argument list, a semicolon does not make sense, it is a syntax error. The argument list itself is made of expressions, though, and therefore if you double them puts((...)) then what we saw above applies to the inner one. Control expressions do not use parentheses in Ruby, so you can use (...) as an expression there as well.

On Wed, Aug 30, 2023 at 2:26 PM Xavier Noria <fxn@hashref.com> wrote:
Yes, when () is meant to yield a expression, you can put several statements in it. For example, consider:
(x = Module.new; p x)::C = 1
It does work as observed and intuitively it should but the documentation does not explicitly say it allows it to.
(a, b) does not play the role of an expression, right? Similarly, in your examples with puts,
puts(...)
is parsed as puts + the argument list of the call. Again, not an expression. In an argument list, a semicolon does not make sense, it is a syntax error.
My example had a space between puts and '('. The documentation says: "If you put a space between the method name and opening parenthesis, you do not need two sets of parentheses." but 'puts (:ignore; :x)' raises an error. -- konsolebox

On Wed, Aug 30, 2023 at 10:43 AM konsolebox <konsolebox@gmail.com> wrote: On Wed, Aug 30, 2023 at 2:26 PM Xavier Noria <fxn@hashref.com> wrote:
Yes, when () is meant to yield a expression, you can put several
statements in it. For example, consider:
(x = Module.new; p x)::C = 1
It does work as observed and intuitively it should but the documentation does not explicitly say it allows it to.
Yes. Unfortunately, the Ruby documentation is far from being comprehensive or precise.
(a, b) does not play the role of an expression, right? Similarly, in your examples with puts,
puts(...)
is parsed as puts + the argument list of the call. Again, not an
expression. In an argument list, a semicolon does not make sense, it is a syntax error.
My example had a space between puts and '('. The documentation says: "If you put a space between the method name and opening parenthesis, you do not need two sets of parentheses." but 'puts (:ignore; :x)' raises an error.
Oh, the space, right. p (1 if true), (2 if false) passes two arguments to p just fine. The specs for this are here <https://github.com/ruby/ruby/blob/00fdb4e12e1933bdb110aeecc08099b4875c91ce/spec/ruby/language/method_spec.rb#L1178> (an authoritative source when documentation is lacking), and I cannot give you an answer to what you found without guessing. It could even be a bug in the parser, because I don't quite see why is a ternary operator parsed, but not an expression with ;. I don't know.

On Wed, Aug 30, 2023 at 11:53 AM Xavier Noria <fxn@hashref.com> wrote:
(a, b) does not play the role of an expression, right? Similarly, in your
examples with puts,
puts(...)
is parsed as puts + the argument list of the call. Again, not an
expression. In an argument list, a semicolon does not make sense, it is a syntax error.
My example had a space between puts and '('. The documentation says: "If you put a space between the method name and opening parenthesis, you do not need two sets of parentheses." but 'puts (:ignore; :x)' raises an error.
Oh, the space, right.
p (1 if true), (2 if false)
passes two arguments to p just fine.
The specs for this are here <https://github.com/ruby/ruby/blob/00fdb4e12e1933bdb110aeecc08099b4875c91ce/spec/ruby/language/method_spec.rb#L1178> (an authoritative source when documentation is lacking), and I cannot give you an answer to what you found without guessing. It could even be a bug in the parser, because I don't quite see why is a ternary operator parsed, but not an expression with ;.
I don't know.
I have opened https://github.com/ruby/spec/pull/1063. If it goes in, it is intentional, but it is not related to the syntax for arbitrary expressions. I exchanged impressions with Kevin Newton, and making parantheses optional in that corner of the grammar is special-cased for single statements. Let's see what we find out!

On Wed, Aug 30, 2023 at 4:23 PM Xavier Noria <fxn@hashref.com> wrote: I have opened https://github.com/ruby/spec/pull/1063.
If it goes in, it is intentional, but it is not related to the syntax for arbitrary expressions. I exchanged impressions with Kevin Newton, and making parantheses optional in that corner of the grammar is special-cased for single statements.
Let's see what we find out!
Yeah, it was merged.
participants (2)
-
konsolebox
-
Xavier Noria