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


## On Pattern Matching in Other Languages

For continuity, we should also go over implementations in other languages.

Note that I am not an expert in any of these languages, and only proficient in Javascript. I would encourage others to source examples and correct any shortcomings of my answers.

### Javascript

I think the most practical one to read right now is the current TC39 proposal for pattern matching in Javascript:

https://github.com/tc39/proposal-pattern-matching

The pull request and discussion around it is particularly enlightening as to the challenges and concerns present in creating such a feature, and as it is a stage 0 proposal it gives a very new view to the idea as well. 

An example:

```javascript
const getLength = vector => match (vector) {
  { x, y, z } => Math.sqrt(x ** 2 + y ** 2 + z ** 2),
  { x, y } => Math.sqrt(x ** 2 + y ** 2),
  [...etc] => vector.length
}

getLength({x: 1, y: 2, z: 3}) // 3.74165
```

It would be disingenuous to not mention that Javascript also has a concept of destructuring:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

This gives it a significant advantage in defining such a pattern, and would be difficult to implement in Ruby potentially with the Hash / Block distinctions. It's possible, yes, but something to keep in mind.

Noted that I'd love destructuring as well, but that may be overkill. I wonder if it may be a prerequisite in some ways though, as Left Hand Assignment is huge to pattern matching.

### Elixir

A language directly inspired by Ruby, perhaps we can borrow back. Elixir has several types of pattern matching.

https://elixir-lang.org/getting-started/pattern-matching.html

The first should look very similar to the Javascript example, as destructuring is basically a form of pattern matching:

```elixir
iex> {a, b, c} = {:hello, "world", 42}
{:hello, "world", 42}
```

Notedly if the sides are not congruent a match will fail. This does introduce the idea that `=` is not really assignment, but a pattern match itself. I don't see that as an easy or really even practical thing to be able to do in Ruby.

The next is quite similar to overloading methods in Java:

https://blog.carbonfive.com/2017/10/19/pattern-matching-in-elixir-five-things-to-remember/

```elixir
# greeter.exs
defmodule Greeter do
  def hello(:jane), do: "Hello Jane"
  
  def hello(name) do
    "Hello #{name}"
  end
end

# calculator.exs
defmodule Calculator do
  def multiply_by_two([]), do: return []

  def multiply_by_two([head | tail]) do 
    [head * 2 | multiply_by_two(tail)]
  end
end
```

A similar idea exists in Haskell and other languages, but we'll get to them later. The concern here is that this type of technique is already done heavily in Ruby using Case as a type dispatcher:

```ruby
def method(*args)
  case args.first
  when String then string_variant(args)
  when Integer then integer_variant(args)
 ...
end
```

Point being that pattern matching may exacerbate that issue that Elixir solves. That's also a very hard feature to account for.

### Haskell

Haskell has several different styles of pattern matching, some of which very similar to the Elixir example right above:

http://learnyouahaskell.com/syntax-in-functions

```haskell
factorial :: (Integral a) => a -> a  
factorial 0 = 1  
factorial n = n * factorial (n - 1)  
```

The guard statement may be more in line with what we would recognize as a case statement:

```haskell
max' :: (Ord a) => a -> a -> a  
max' a b   
    | a > b     = a  
    | otherwise = b 
```

This also treats `=` as a pattern match, and relies on some of Haskell's laziness. Perhaps case expressions are the closest parallel though:

```haskell
describeList :: [a] -> String  
describeList xs = "The list is " ++ case xs of [] -> "empty."  
                                               [x] -> "a singleton list."   
                                               xs -> "a longer list."  
```

### Scala

Scala is likely one of the closest to Ruby in terms of syntax in pattern matching:

https://docs.scala-lang.org/tour/pattern-matching.html

```scala
def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}

matchTest(3)  // many
matchTest(1)  // one
```

Case classes especially are interesting in that some Ruby variants may be able to copy such techniques with constructor contracts and `self.to_proc`:

```scala
abstract class Notification

case class Email(sender: String, title: String, body: String) extends Notification

case class SMS(caller: String, message: String) extends Notification

case class VoiceRecording(contactName: String, link: String) extends Notification

def showNotification(notification: Notification): String = {
  notification match {
    case Email(email, title, _) =>
      s"You got an email from $email with title: $title"
    case SMS(number, message) =>
      s"You got an SMS from $number! Message: $message"
    case VoiceRecording(name, link) =>
      s"you received a Voice Recording from $name! Click the link to hear it: $link"
  }
}

val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")

println(showNotification(someSms))  // prints You got an SMS from 12345! Message: Are you there?

println(showNotification(someVoiceRecording))  // you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
```

I could see implementations being possible off of some of Scala, but case classes aren't as useful outside the context of static types or validations. This means relying on arity or other special contracts to ensure the right thing gets matched, which could be inaccurate at times.

## Wrap Up

Noted that there are several other languages that have features such as this, but I see these as some of the more prominent ones. OCaml, F#, and other languages also feature pattern matching, and would be worth looking into.

Most of Qo's implementation is loosely based off of Scala and Haskell techniques.

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

* 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>