Issue #14709 has been updated by baweaver (Brandon Weaver).


On considering a bit more, I've come up with a few syntax variants for such a feature.

Preference towards avoiding `%p` and other shorthands in favor of a more self-descriptive word like `matches` or `match`.

### 1. matches

There are a few variants of this I can think of.

**1A - Matches Guard Block**

The first involves the guard-block style syntax:

```ruby
case value
when matches(/Foo/, 42) { |name, age| }
else matches { |object| }
end
```

**1B - Matches then local inject**

The second would involve the use of `then` or indent:

```ruby
case value

# First option is to use then as a demarcation like if and case/when:
when matches(/Foo/, 42) then Person.new(name, age)

# alternatively, line break:
when matches(/Foo/, 42)
  Person.new(name, age)

else matches
  # alternate case
end
```

Considerations for this second method are how you would define local variables. Blocks give you control over this, but Ruby does not currently have a clean way to define local variables based off the results of a function.

With something like case classes it'd be a matter of reflection on arity and param names from the initializer, but this would be slow. It'd also be potentially rife with namespace collisions and shadowing by trying to be too clever.

### 2. Enumerator-like yielder:

Enumerator has the following syntax which exposes a bind point:

```ruby
one_then_two_forever = Enumerator.new do |y|
  y.yield(1)
  loop { y.yield(2) }
end
```

What if we extrapolate from that?:

```ruby
match(value) do |m|
  m.when(/name/, 42) { |name, age| Person.new(name, age) }
  m.else { |object| raise "Can't convert!" }
end
```

This would be similar to concepts used for benchmark, websockets, async, and other tasks by providing a yielder point. It is also very succinct.

It may be a bit magic, but when passed no argument `match` could return a `Proc` instead awaiting a value. That would allow for some really interesting things like this:

```ruby
def get_url(url)
  Net::HTTP.get_response(URI(url)).then(&match do |m|
    m.when(Net::HTTPSuccess) { |response| response.body.size }
    m.else { |response| raise response.message }
  ))
end
```

Any one of the `when` cases could be used with `===`, behaving very much like a case statement's `when`. Right-hand destructuring may still be interesting here though, I'll have to think on that.

This syntax would expose a very minimal changeset to the language itself, requiring only a single word and utilizing already common patterns.

----------------------------------------
Feature #14709: Proper pattern matching
https://bugs.ruby-lang.org/issues/14709#change-71644

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
On RubyKaigi 2017, there was a [presentation](http://rubykaigi.org/2017/presentations/yotii23.html) of Yuki Torii about possible implementation of pattern matching.

The syntax proposed in presentation was:

```ruby
res = [:ng, 500]
case res
when %p([:ng, status])
  p status
end
```

The proposed syntax seem to feel pretty consistent, and the implementation (forked Ruby interpreter) was working at this moment.

As @ko1 was one of the contributors to the experiment, I don't suppose Ruby core team is not aware of the proposal, so I'd like to know what the status of it? Are there some plans for full-strength pattern matching in Ruby 3 (with proposed, or any other, syntax)?

PS: There are many existing gems with some kind "almost real" pattern matching (including recently emerged [Qo](https://github.com/baweaver/qo)), yet I believe that the _only_ useful pattern matching can be provided language core. Otherwise, two main goals can't be achieved:
* reasonable performance (as the pattern-matching is useful mostly in complicated algorithms, which tend to repeat matches thousands of times);
* unpacking of parts of the patterns into local variables.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>