DEV Community

Ruby – Pattern Matching – Second Impressions

Paweł Świątkowski on April 18, 2019

Since I published A quest for pattern-matching in Ruby 3 years ago, I've been called "pattern matching guy" more than once. So obviously, when I le...
Collapse
 
edisonywh profile image
Edison Yap

Wow, that was really hard to understand!

I'm sure whoever made this happen had put in a lot of effort, but as you said, I don't think it's ideal to just shoehorn a feature in when it doesn't fit in.

By the way, with a quick glance on your snippets below, it looks like what you're asking for isn't really just pattern matching, but rather method overload.

I know Crystal has it which looks pretty cool!

Collapse
 
katafrakt profile image
Paweł Świątkowski

From what I know about Crystal, it has method overload only by types (much like Java). And hear it would be possible to also "overload" by particular values - for example different method for hash containing a key "success".

Collapse
 
edisonywh profile image
Edison Yap

Correct, that's what overloading means - defining methods with same name but with different method signatures, and method signatures are usually types & arity.

What you're referring to (in Elixir) is a combination of both - when you have pattern matching, your method signatures aren't just types & arity, but also patterns.

Collapse
 
vidarh profile image
Vidar Hokstad

No need for language support for your "typeunion" suggestion (though really, it's more generic than that), and of course you can do the same as in my example just with "when String,Integer"; the only thing this buys you is the ability to pass the list around as an object:

class TypeUnion
  def initialize(*args)
    @types = args
  end

  def ===(arg)
    @types.detect{|t| t === arg}
  end
end

def typeunion(*args)
  return TypeUnion.new(*args)
end

def test(arg)
  case arg
  when typeunion(String, Integer)
    puts "String or Integer: #{arg}"
  else
    puts "What's this? #{arg.inspect}"
  end
end

test(4)
test("foo")
test(1.0)
test(false)

As for your suggestion for multiple dispatch, I don't think it's a hard change at all. I'm working on a Ruby compiler, and the way I'd implement something like that would simply be to create hidden methods with the type signature for rewrites at call-sites where I can prove the types at compile time, and make the "plain" method a generated method that does the type checks and dispatches to each implementation. Conceptually it's really just wrapping every variant in a big "case", and not hard at all.

The hard part is getting people to agree to add it.

Collapse
 
katafrakt profile image
Paweł Świątkowski

Thanks for giving a proper name for what I'm looking for. Neither pattern matching nor method overload mentioned above did not seem correct. Multiple dispatch clicks.

Perhaps you're right that it soudn't be so hard to implement. But wouldn't it break backwards compatibility somehow? Ruby core team is known for keeping it at all costs.

Collapse
 
vidarh profile image
Vidar Hokstad

It would break semantics if overloads are allowed in a way that is syntactically valid in older code. So the challenge would be to pick syntax to specify the type signatures that can not occur in old working code.

Finding syntax that doesn't look awful but that is currently invalid would actually likely be the hardest part of adding support for it.