[前][次][番号順一覧][スレッド一覧]

ruby-changes:63492

From: Kazuki <ko1@a...>
Date: Sun, 1 Nov 2020 13:36:00 +0900 (JST)
Subject: [ruby-changes:63492] b601532411 (master): Pattern matching is no longer experimental

https://git.ruby-lang.org/ruby.git/commit/?id=b601532411

From b60153241121297c94de976419d421683da4d51b Mon Sep 17 00:00:00 2001
From: Kazuki Tsujimoto <kazuki@c...>
Date: Sun, 1 Nov 2020 13:28:24 +0900
Subject: Pattern matching is no longer experimental


diff --git a/NEWS.md b/NEWS.md
index c7a4036..2fa1b3d 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -48,7 +48,23 @@ sufficient information, see the ChangeLog file or Redmine https://github.com/ruby/ruby/blob/trunk/NEWS.md#L48
   instead of a warning. yield in a class definition outside of a method
   is now a SyntaxError instead of a LocalJumpError.  [[Feature #15575]]
 
-* Find pattern is added. [[Feature #16828]]
+* Pattern matching is no longer experimental. [[Feature #17260]]
+
+* One-line pattern matching now uses `=>` instead of `in`.  [EXPERIMENTAL]
+  [[Feature #17260]]
+
+    ```ruby
+    # version 3.0
+    {a: 0, b: 1} => {a:}
+    p a # => 0
+    
+    # version 2.7
+    {a: 0, b: 1} in {a:}
+    p a # => 0
+    ```
+
+* Find pattern is added.  [EXPERIMENTAL]
+  [[Feature #16828]]
 
     ```ruby
     case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index 9d3101c..8419af5 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -1,12 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L1
 = Pattern matching
 
-Pattern matching is an experimental feature allowing deep matching of structured values: checking the structure and binding the matched parts to local variables.
+Pattern matching is a feature allowing deep matching of structured values: checking the structure and binding the matched parts to local variables.
 
-Pattern matching in Ruby is implemented with the +in+ operator, which can be used in a standalone expression:
-
-    <expression> in <pattern>
-
-or within the +case+ statement:
+Pattern matching in Ruby is implemented with the +case+/+in+ expression:
 
     case <expression>
     in <pattern1>
@@ -19,11 +15,15 @@ or within the +case+ statement: https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L15
       ...
     end
 
-(Note that +in+ and +when+ branches can *not* be mixed in one +case+ statement.)
+or with the +=>+ operator, which can be used in a standalone expression:
+
+    <expression> => <pattern>
 
-Pattern matching is _exhaustive_: if variable doesn't match pattern (in a separate +in+ statement), or doesn't matches any branch of +case+ statement (and +else+ branch is absent), +NoMatchingPatternError+ is raised.
+(Note that +in+ and +when+ branches can *not* be mixed in one +case+ expression.)
 
-Therefore, +case+ statement might be used for conditional matching and unpacking:
+Pattern matching is _exhaustive_: if variable doesn't match pattern (in a separate +in+ clause), or doesn't matches any branch of +case+ expression (and +else+ branch is absent), +NoMatchingPatternError+ is raised.
+
+Therefore, +case+ expression might be used for conditional matching and unpacking:
 
   config = {db: {user: 'admin', password: 'abc123'}}
 
@@ -37,11 +37,11 @@ Therefore, +case+ statement might be used for conditional matching and unpacking https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L37
   end
   # Prints: "Connect with user 'admin'"
 
-whilst standalone +in+ statement is most useful when expected data structure is known beforehand, to just unpack parts of it:
+whilst the +=>+ operator is most useful when expected data structure is known beforehand, to just unpack parts of it:
 
   config = {db: {user: 'admin', password: 'abc123'}}
 
-  config in {db: {user:}} # will raise if the config's structure is unexpected
+  config => {db: {user:}} # will raise if the config's structure is unexpected
 
   puts "Connect with user '#{user}'"
   # Prints: "Connect with user 'admin'"
@@ -113,7 +113,7 @@ Both array and hash patterns support "rest" specification: https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L113
   end
   #=> "matched"
 
-In +case+ (but not in standalone +in+) statement, parentheses around both kinds of patterns could be omitted
+In +case+ (but not in +=>+) expression, parentheses around both kinds of patterns could be omitted
 
   case [1, 2]
   in Integer, Integer
@@ -378,53 +378,23 @@ Additionally, when matching custom classes, expected class could be specified as https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L378
 
 == Current feature status
 
-As of Ruby 2.7, feature is considered _experimental_: its syntax can change in the future, and the performance is not optimized yet. Every time you use pattern matching in code, the warning will be printed:
+As of Ruby 3.0, one-line pattern matching and find pattern are considered _experimental_: its syntax can change in the future. Every time you use these features in code, the warning will be printed:
 
-  {a: 1, b: 2} in {a:}
-  # warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
+  [0] => [*, 0, *]
+  # warning: Find pattern is experimental, and the behavior may change in future versions of Ruby!
+  # warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
 
 To suppress this warning, one may use newly introduced Warning::[]= method:
 
   Warning[:experimental] = false
-  eval('{a: 1, b: 2} in {a:}')
+  eval('[0] => [*, 0, *]')
   # ...no warning printed...
 
 Note that pattern-matching warning is raised at a compile time, so this will not suppress warning:
 
   Warning[:experimental] = false # At the time this line is evaluated, the parsing happened and warning emitted
-  {a: 1, b: 2} in {a:}
+  [0] => [*, 0, *]
 
 So, only subsequently loaded files or `eval`-ed code is affected by switching the flag.
 
 Alternatively, command-line key <code>-W:no-experimental</code> can be used to turn off "experimental" feature warnings.
-
-One of the things developer should be aware of, which probably to be fixed in the upcoming versions, is that pattern matching statement rewrites mentioned local variables on partial match, <i>even if the whole pattern is not matched</i>.
-
-  a = 5
-  case [1, 2]
-  in String => a, String
-    "matched"
-  else
-    "not matched"
-  end
-  #=> "not matched"
-  a
-  #=> 5  -- even partial match not happened, a is not rewritten
-
-  case [1, 2]
-  in a, String
-    "matched"
-  else
-    "not matched"
-  end
-  #=> "not matched"
-  a
-  #=> 1  -- the whole pattern not matched, but partial match happened, a is rewritten
-
-Currently, the only core class implementing +deconstruct+ and +deconstruct_keys+ is Struct.
-
-   Point = Struct.new(:x, :y)
-   Point[1, 2] in [a, b]
-   # successful match
-   Point[1, 2] in {x:, y:}
-   # successful match
diff --git a/parse.y b/parse.y
index 256e991..98fd4ae 100644
--- a/parse.y
+++ b/parse.y
@@ -502,7 +502,6 @@ static NODE *new_find_pattern(struct parser_params *p, NODE *constant, NODE *fnd https://github.com/ruby/ruby/blob/trunk/parse.y#L502
 static NODE *new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc);
 static NODE *new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc);
 static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc);
-static NODE *new_case3(struct parser_params *p, NODE *val, NODE *pat, const YYLTYPE *loc);
 
 static NODE *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
 static NODE *args_with_numbered(struct parser_params*,NODE*,int);
@@ -1661,7 +1660,11 @@ expr		: command_call https://github.com/ruby/ruby/blob/trunk/parse.y#L1660
 		    {
 			p->ctxt.in_kwarg = $<ctxt>3.in_kwarg;
 		    /*%%%*/
-			$$ = new_case3(p, $1, NEW_IN($5, 0, 0, &@5), &@$);
+			$$ = NEW_CASE3($1, NEW_IN($5, 0, 0, &@5), &@$);
+
+			if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL))
+			    rb_warn0L(nd_line($$), "One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!");
+
 		    /*% %*/
 		    /*% ripper: case!($1, in!($5, Qnil, Qnil)) %*/
 		    }
@@ -2998,7 +3001,7 @@ primary		: literal https://github.com/ruby/ruby/blob/trunk/parse.y#L3001
 		  k_end
 		    {
 		    /*%%%*/
-			$$ = new_case3(p, $2, $4, &@$);
+			$$ = NEW_CASE3($2, $4, &@$);
 		    /*% %*/
 		    /*% ripper: case!($2, $4) %*/
 		    }
@@ -4176,6 +4179,9 @@ p_args_tail	: p_rest https://github.com/ruby/ruby/blob/trunk/parse.y#L4179
 p_find		: p_rest ',' p_args_post ',' p_rest
 		    {
 			$$ = new_find_pattern_tail(p, $1, $3, $5, &@$);
+
+			if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL))
+			    rb_warn0L(nd_line($$), "Find pattern is experimental, and the behavior may change in future versions of Ruby!");
 		    }
 		;
 
@@ -11679,16 +11685,6 @@ new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, co https://github.com/ruby/ruby/blob/trunk/parse.y#L11685
     return node;
 }
 
-static NODE *
-new_case3(struct parser_params *p, NODE *val, NODE *pat, const YYLTYPE *loc)
-{
-    NODE *node = NEW_CASE3(val, pat, loc);
-
-    if (rb_warning_category_enabled_p(RB_WARN_CATEGORY_EXPERIMENTAL))
-	rb_warn0L(nd_line(node), "Pattern matching is experimental, and the behavior may change in future versions of Ruby!");
-    return node;
-}
-
 static NODE*
 dsym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc)
 {
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index d4de685..b155cb8 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -1473,13 +1473,13 @@ END https://github.com/ruby/ruby/blob/trunk/test/ruby/test_pattern_matching.rb#L1473
     assert_warn('') {eval(code)}
 
     Warning[:experimental] = true
-    assert_warn(/Pattern matching is experimental/) {eval(code)}
+    assert_warn(/is experimental/) {eval(code)}
   ensure
     Warning[:ex (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]