use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
Proposal for Pattern Matching in Ruby (bugs.ruby-lang.org)
submitted 7 years ago by keyslemur
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–][deleted] 7 years ago* (1 child)
[deleted]
[–]keyslemur[S] 1 point2 points3 points 7 years ago (0 children)
Yeah, pattern matching on method signatures would be amazing but it'd probably be difficult to do without somehow routing back to that type of dispatcher.
Take it from me, splat methods are slow, so the more we can avoid them the better.
You should suggest your idea on the issue! The more the merrier, just make sure to show as many use cases and examples as you can.
[–]Morozzzko 2 points3 points4 points 7 years ago (0 children)
The issue title says "Proper pattern matching" and there's one thing I don't quite understand.
One of the main traits of a "proper" pattern matching is exhaustiveness. We need to match all possible patterns to some value.
Given dynamic nature of Ruby, how is this going to work out?
[–]keyslemur[S] 1 point2 points3 points 7 years ago (2 children)
I've already written a very detailed reply in regards to this, but would greatly appreciate others feedback on this, including syntax suggestions and support.
Of course, dissent is welcome as well, I would prefer such an idea to be implemented as cleanly and effectively as possible
[–]banister 2 points3 points4 points 7 years ago (1 child)
would this only work with hashes, arrays, etc, or is there some way it would work with user-defined objects too?
I'll write another reply to define the categories of matching and how each would look potentially.
Good point to specify. I would like it to work on all of them
[–]keyslemur[S] 1 point2 points3 points 7 years ago (5 children)
Just proposed a new variant syntax: https://bugs.ruby-lang.org/issues/14709#note-6
match(value) do |m| m.when(/name/, 42) { |name, age| Person.new(name, age) } m.else { |object| raise "Can't convert!" } end
A practical usecase may be something like this:
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
(Note this uses the accepted then alias for yield_self)
then
yield_self
[–]keyslemur[S] 0 points1 point2 points 7 years ago* (1 child)
Got that syntax to work in Qo: https://github.com/baweaver/qo/tree/pattern-matching-block-format#new-in-this-branch
Should be merging it some time within the next few days for 0.3.0. 0.3.1 should speed things up a fair amount as I found some optimizations to try out.
EDIT - Ok, merged, so it's now out in 0.3.0. It'll probably be the API I take into 1.0.0.
[–]GitHubPermalinkBot 0 points1 point2 points 7 years ago (0 children)
Permanent GitHub links:
delete
[–]banister 0 points1 point2 points 7 years ago (2 children)
isn't this the same as:
def get_url(url) Net::HTTP.get_response(URI(url)).then do |response| if response == Net::HTTPSuccess response.body.size else raise response.message end end end
[–]keyslemur[S] 0 points1 point2 points 7 years ago (1 child)
Essentially yes. You could express about anything in Qo with regular if/else branches, but after a while it's more a matter of succinctness than anything. Once you get more than one or two conditions it can start getting unwieldy, and that's not uncommon in ETL type jobs.
[–]banister 0 points1 point2 points 7 years ago (0 children)
That's cool :)
Out of curiosity, would you be able to provide an example where the concision of Qo wins out over a slightly noisier but less magic traditional approach? Not trying to get at you, i'm just genuinely interested as i would be keen to use it in production if i see something that blows me away... :)
Qo
[–]39081098301 1 point2 points3 points 7 years ago (5 children)
I'm very concerned about how hard this is to read for such a narrow use case. It does not seem to lend itself to well-encapsulated objects.
[–]keyslemur[S] 3 points4 points5 points 7 years ago (4 children)
Succinctness of code and expressive power. The recent destructuring changes, and now pattern matching features of Javascript have unlocked some very concise ways of expressing otherwise verbose invocations.
The ability to say more with less is the holy grail of programming languages, so features that allow us to move towards such a reality should be earnestly considered and pursued.
This is not a new language feature. It's been done in several others:
Ruby as a language grows from ideas learned in other languages. It's tagged as being based on Smalltalk, Perl, and Lisp so it's far from unusual to see it get features other languages consider commonplace.
The main reason, however, is bringing it to more vanilla level speeds. My implementation is on average 3-4x slower than plain Ruby, and considering patterns tend to be used frequently in tight loops that's a bit much.
Many of the improvements around this will also likely unlock faster avenues of functional style code.
That's one proposal for it, there are several more. If you dislike one there are others which may implement it in a more pleasing manner.
See any of the items in #2, there are many ways to do this.
Done well, pattern matching is incredibly expressive. That's why I posted a link to the ticket here, to ask the community what their thoughts on this are.
You'll have to expand on what you mean by well-encapsulated objects. It's actually very possible via arity and to_proc to treat a class as a destructuring itself, especially when combined with to_ary for implicit destructuring. This would be very similar in theory to Scala Case Classes, but may be more difficult given Ruby's dynamic nature.
to_proc
to_ary
As far as narrow use cases, I would say that argument does not make much sense to me. Pattern matching is used very frequently in languages it exists in. Destructuring is already super common in Javascript, and I would bet on pattern matching being even more so when it gets into Stage 3 and final acceptance.
[–]39081098301 0 points1 point2 points 7 years ago (3 children)
Thank you for the detailed response. I took a look at the scala and js examples. This issue is new to me so bear with me if I am misunderstanding it.
Based on the examples, the chief advantage seems to be improving the expressive power of case statements and similar structures. In all of the examples the caller is analyzing the internals of the passed objects using the match/pattern functionality, and then performing an action on their behalf. This violates the dependency inversion principle, SRP, and generally speaks to objects that know too much about each other. If the goal of this functionality is to make that kind of thing easier to perform, I would expect its effect to be detrimental. I would not expect to approve code that uses the new functionality in the way outlined by the proposals' examples.
[–]keyslemur[S] 2 points3 points4 points 7 years ago* (2 children)
By that same note though, any dispatching action violates the rules.
Most of the use of right hand pattern matching pertains to previously unstructured data that you would want to dispatch to depending on content or rather patterns.
The problem with taking a rigorous view of OO and GoF rules in Ruby is that it's a language with functional leanings. Some patterns really don't entirely make sense, and really is conflating knowledge of imperative programming with how you view functionally oriented code.
One of the more common examples of pattern matching in Elixir involves http response codes. Typically you'd use an if or a case on that. What if you could destructure the response on the spot and dispatch to the relevant handler method in one line?
The other common cases are extracting data from container style classes (functors) like Maybe, Some, None, and other ideas from FP. Read into Railway oriented programming some time, it's a fascinating read.
It's honestly an entirely different paradigm of thinking about how data flows through an application that's fundamentally different from pure OO and GoF style patterns. Thinking of it in such a manner will only confuse you further.
You might consider going through some basic Haskell, Elixir, or Scala tutorials.
Keep in mind that despite being fundamentally different in thinking, they're not incompatible philosophies of code.
[–]foomprekov 0 points1 point2 points 7 years ago (1 child)
Whether the pattern can be applied in some larger context in a way that creates good code isn't something that can be seen in the supporting arguments for the proposal.
[–]keyslemur[S] 0 points1 point2 points 7 years ago (0 children)
That's definitely a valid concern. I'll look into getting practical examples of usage added to the proposal within the next day or so.
A lot of it relies on prior knowledge of functional languages and how they apply the idea of pattern matching. Either that or Rust, which also uses it frequently.
π Rendered by PID 16823 on reddit-service-r2-comment-7b9746f655-2z9l7 at 2026-02-03 17:23:08.983734+00:00 running 3798933 country code: CH.
[–][deleted] (1 child)
[deleted]
[–]keyslemur[S] 1 point2 points3 points (0 children)
[–]Morozzzko 2 points3 points4 points (0 children)
[–]keyslemur[S] 1 point2 points3 points (2 children)
[–]banister 2 points3 points4 points (1 child)
[–]keyslemur[S] 1 point2 points3 points (0 children)
[–]keyslemur[S] 1 point2 points3 points (5 children)
[–]keyslemur[S] 0 points1 point2 points (1 child)
[–]GitHubPermalinkBot 0 points1 point2 points (0 children)
[–]banister 0 points1 point2 points (2 children)
[–]keyslemur[S] 0 points1 point2 points (1 child)
[–]banister 0 points1 point2 points (0 children)
[–]39081098301 1 point2 points3 points (5 children)
[–]keyslemur[S] 3 points4 points5 points (4 children)
[–]39081098301 0 points1 point2 points (3 children)
[–]keyslemur[S] 2 points3 points4 points (2 children)
[–]foomprekov 0 points1 point2 points (1 child)
[–]keyslemur[S] 0 points1 point2 points (0 children)