[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#label-Modifier+Statements

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.

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.

···

On Wed, Aug 30, 2023 at 2:26 PM Xavier Noria <fxn@hashref.com> wrote:

--
konsolebox
______________________________________________
ruby-talk mailing list -- ruby-talk@ml.ruby-lang.org
To unsubscribe send an email to ruby-talk-leave@ml.ruby-lang.org
ruby-talk info -- Info | ruby-talk@ml.ruby-lang.org - ml.ruby-lang.org

>
> 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&gt;
(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 10:43 AM konsolebox <konsolebox@gmail.com> wrote:
On Wed, Aug 30, 2023 at 2:26 PM 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&gt; (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 Add more specs for method calls with a space by fxn · Pull Request #1063 · ruby/spec · GitHub.

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 11:53 AM Xavier Noria <fxn@hashref.com> wrote:

I have opened Add more specs for method calls with a space by fxn · Pull Request #1063 · ruby/spec · GitHub.

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.

···

On Wed, Aug 30, 2023 at 4:23 PM Xavier Noria <fxn@hashref.com> wrote: