Project

General

Profile

Actions

Bug #17925

open

Pattern matching syntax using semicolon one-line

Added by koic (Koichi ITO) over 3 years ago. Updated about 1 year ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 3.1.0dev (2021-05-28T16:34:27Z master e56ba6231f) [x86_64-darwin19]
[ruby-dev:51061]

Description

Summary

There are the following differences between case ... when and case ... in. Is this an expected behavior?

% ruby -v
ruby 3.1.0dev (2021-05-28T16:34:27Z master e56ba6231f) [x86_64-darwin19]

% ruby -ce 'case expression when 42; end'
Syntax OK

% ruby -ce 'case expression in 42; end'
-e:1: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
-e:1: syntax error, unexpected `end', expecting `when'
case expression in 42; end

So, I have two concerns.

  • Since the pattern matching syntax is different from case ... when, can't user write semicolon one-line case ... in in the same semicolon one-line as case ... when?
  • Does case expression in 42; end display an experimental warning of one-line pattern matching. Right?

This is reproduced in Ruby 3.1.0-dev and Ruby 3.0.1.

Additional Information

NOTE 1: I understand that only syntax that doesn't use case and end is experimental one-line pattern matching syntax.

% ruby -ce 'expression in 42'
-e:1: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
Syntax OK

NOTE 2: The syntax is OK if a semicolon is used between expression and in. But case ... when is a valid syntax to omit.

% ruby -e ruby -ce 'case expression; in 42; end'
Syntax OK

Updated by koic (Koichi ITO) over 3 years ago

NOTE 1: I understand that only syntax that doesn't use case and end is experimental one-line pattern matching syntax.

A little supplement. The following is also an experimental one-line pattern matching syntax since Ruby 3.0, but the => one-line pattern matching syntax is no problem.

% ruby -e "'' => ''"
-e:1: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!

Updated by nobu (Nobuyoshi Nakada) over 3 years ago

It is a known restriction that the code is parsed as case (expression in 42).
Let me consider if it is possible to make that a priority.

Updated by jeremyevans0 (Jeremy Evans) about 1 year ago

@kddnewton (Kevin Newton) Is this possible to fix in YARP?

@yui-knk (Kaneko Yuichiro) Is this possible to fix in parse.y/lrama?

Updated by nobu (Nobuyoshi Nakada) about 1 year ago

I thought it a trade-off.
To allow the statement, one-line pattern matching is not allowed there.
But it returns true/false only and may be useless for case.

Updated by kddnewton (Kevin Newton) about 1 year ago

This is interesting. It surfaces an incompatibility we have. I didn't realize Ruby didn't allow this, so YARP allows case expression in 42; end to parse as expected by the OP here. If parse.y can't support this, I will need to explicitly disallow this in YARP.

Updated by yui-knk (Kaneko Yuichiro) about 1 year ago

It's possible https://github.com/yui-knk/ruby/tree/bugs_17925.
I think this is not limitaion but the matter of choice. Currently expr is expected after case therefore expression in 42 is interpreted as expr.

For example

case expression in 42
in true
in false
end

Before the change, this is interpreted as

case (expression in 42)
in true
in false
end

After the change, this is interpreted as

case expression
in 42
in true
in false
end

Impact

For case ... in

As shown above, this will change the behavior of current codes.

Before:

expression = 42

case expression in 42
in true
  p :t
in false
  p :f
end

#=> :t
expression = 421

case expression in 42
in true
  p :t
in false
  p :f
end

#=> :f

After:

expression = 42

case expression in 42
in true
  p :t
in false
  p :f
end

#=> nothing printed, because body for 42 is empty
expression = 421

case expression in 42
in true
  p :t
in false
  p :f
end

#=> 421 (NoMatchingPatternError)
# because nothing matches

For case ... when

Before this change, this is valid

case expression in 42
when true
  p :t
when false
  p :f
end

However after this change, it's invalid

case expression in 42
when true
  p :t
when false
  p :f
end

# test2.rb:2: syntax error, unexpected `when' (SyntaxError)
# when true
# ^~~~

Impact on case ... when is inevitable because new grammar recognizes this is case ... in when third symbol (in) appears.

New exception

expr appears other place of the grammar. For example, if expr ..., while expr ... and so on. This change introduces an exception that you can write one line pattern matching after if, unless, while, until and so on but you can't after case.

Conclusion

  • This a matter of choice not limitaion
  • New grammar introduces incompatibility. It changes the behavior of case ... in and breaks case ... when
  • It introduces an exceptional rule to the grammar
  • As a reporter says, there is workaround to add ; after expression

expression in 42 always returns true or false therefore it might be useless for case. Howerver we need to consider such impacts and benefits before decision making.

Note

Impact on case ... when can be found as Shift/Reduce conflict. In this state, shift derives case ... when, on the other hand reduce derives case ... in.

https://github.com/yui-knk/ruby/tree/bugs_17925_2

State 394

    shift/reduce conflict on token "`in'":
       60 expr0: arg •
       71 expr: arg • "`in'" @7 @8 p_top_expr_body
      First example: $@1 k_case arg • "`in'" @7 @8 p_top_expr_body opt_terms @19 case_body k_end "=>" @5 @6 p_top_expr_body opt_terms
      Shift derivation
        program
        ↳ 2: $@1 top_compstmt
                 ↳ 3: top_stmts                                                                                                                                          opt_terms
                      ↳ 5: top_stmt
                           ↳ 7: stmt
                                ↳ 37: expr
                                      ↳ 68: arg                                                                                               "=>" @5 @6 p_top_expr_body
                                            ↳ 269: primary
                                                   ↳ 358: k_case expr_value                                     opt_terms @19 case_body k_end
                                                                 ↳ 78: expr
                                                                       ↳ 71: arg • "`in'" @7 @8 p_top_expr_body
      Second example: $@1 k_case arg • opt_terms "`in'" @38 @39 p_top_expr then $@40 compstmt p_cases k_end '[' opt_call_args rbracket "operator-assignment" lex_ctxt command_rhs opt_terms "end-of-input"
      Reduce derivation
        $accept
        ↳ 0: program                                                                                                                                                                                                                                "end-of-input"
             ↳ 2: $@1 top_compstmt
                      ↳ 3: top_stmts                                                                                                                                                                                                      opt_terms
                           ↳ 5: top_stmt
                                ↳ 7: stmt
                                     ↳ 32: command_asgn
                                           ↳ 41: primary_value                                                                                                      '[' opt_call_args rbracket "operator-assignment" lex_ctxt command_rhs
                                                 ↳ 377: primary
                                                        ↳ 361: k_case expr_value0       opt_terms p_case_body                                                 k_end
                                                                      ↳ 77: expr0                 ↳ 500: "`in'" @38 @39 p_top_expr then $@40 compstmt p_cases
                                                                            ↳ 60: arg •


Updated by kddnewton (Kevin Newton) about 1 year ago

I agree with @yui-knk (Kaneko Yuichiro) here, I think this is definitely a choice and at this point can't be changed.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0