I am the author of aforementioned Qo, so I believe I can shed some light on a few things:

The thinking behind Qo

Reusable syntax features

Making it feel like Ruby

Shortcomings of current syntax

Performance considerations

Ideas moving forward

I will warn you that this may be a very long post, so I will attempt to break it into the above sections to make it easier to read. The last section will propose my ideas on syntax, and will effectively summarize the others.

You can find Qo here: https://github.com/baweaver/qo

I have tried to be detailed in my documentation, and will continue to expand upon it.

The thinking behind Qo¶

Qo emerged as a result of the TC39 proposal for pattern matching as well as a conversation I had at Fog City Ruby about real pattern matching in Ruby, and made me ask a few questions:

How can we do this using what Ruby already has?

How can we make this look and feel like Ruby?

How can we make the performance acceptable?

I wrote an article that explains, in more detail than I will here, the first point: https://medium.com/@baweaver/for-want-of-pattern-matching-in-ruby-the-creation-of-qo-c3b267109b25

How can we use current Ruby syntax and make it feel like Ruby?¶

Ruby is an exceptionally powerful language, and jumping back to the basics we can find === and to_proc . Both are used throughout current language features with implicit syntax:

# === is implied around case statements case 'string' when String then 1 else 2 end # in grep data . grep ( String ) # and now in predicate methods data . any? ( String )

For to_proc it's a very similar story:

data . map ( & ProcObject )

Both are well understood in Ruby and utilize common features. Implementing classes that expose such methods allow them to utilize these same features for more powerful APIs.

to_ary was one of my next potentials for destructuring and right hand assignment emulation in pattern matching, but I have not yet found an acceptable solution to this.

Point being, by using existing language features we retain a very Ruby-like feel:

case Person . new ( '' , nil ) when Qo [ age: :nil? ] then 'No age provided!' else 'nope' end

Though this brings us to the next point: limitations of current syntax.

Limitations of current syntax¶

One of the key items of pattern matching that I would very much enjoy is Right Hand Assignment, or the ability to inject local variables in the resulting branch of a match.

Case statements will not allow this, so something such as this is not possible as when will not be able to return a value:

people . map { | person | case person when Qo . m ( name: : * , age: 20 .. 99 ) { | person | " #{ person . name } is an adult that is #{ person . age } years old" } else Qo . m (: * ) end }

This was the reason behind me introducing the concept of match with Qo:

Qo . match ([ 'Robert' , 22 ], Qo . m (: * , 20 .. 99 ) { | n , a | " #{ n } is an adult that is #{ a } years old" }, Qo . m (: * ) ) # => "Robert is an adult that is 22 years old" people . map ( & Qo . match ( Qo . m (: * , 20 .. 99 ) { | n , a | " #{ n } is an adult that is #{ a } years old" }, Qo . m (: * ) )) # => "Robert is an adult that is 22 years old"

It is not as elegant and Ruby-like as I would like, but it is more succinct than some of the other implementations based in more functional language paradigms using purely lambda composition.

As a result, it also ends up being faster which leads me to the next section:

Performance Considerations¶

I try and be very honest about the performance concerns related to Qo, being that it is heavily dynamic in nature. Admittedly in ways it tries to be too clever, which I am attempting to reconcile for greater performance gains.

The performance results can be seen here: https://github.com/baweaver/qo/blob/master/performance_report.txt

All tests are specified in the Rakefile and compare Qo to a Vanilla variant of the same task. The performance was better than I had anticipated but still did not reach quite the speed that I had wanted it to.

I will continue to test against this and make improvements. It is likely that I can cut down this time substantially from where it currently is.

It is also the reason you may see certain === related tickets on speed improvement :)

I will endeavor to bring more comprehensive performance testing, especially around pattern matching as I have no results to this point.

Ideas moving forward¶

I would be interested in a match syntax such as this:

new_value = match value when % m ( :_ , 20 .. 99 ) { | _ , age | age + 1 } else { | object | ... } end

The block syntax will make this a less magical option as it can explicitly capture details on what was matched. Keyword arguments could be used as well, but few know of the keyword arguments in blocks:

json . map { | name: 'default_name' , age: 42 | Person . new ( name , age ) }

Such syntax exists most similarly in Scala, notably with Case Classes. Other similar implementations are present in the JS TC39 proposal and to a lesser extent in Haskell.

I have yet to think of a way to implement Left Hand Assignment like Javascript destructuring, and I do not have ideas on how to achieve such a thing beyond using to_ary for implicit destructuring.

Thank you for your time in reading, and I apologize for my verbosity, but this is a feature I would very much like to see in Ruby Core some day.

I would be more than happy to provide alternative ideas on syntax in regards to this idea if you do not find the proposed ones satisfactory.