Exploration: Library-based Pattern Matching
- Dominant language
- No language data
- Stars
- 328
- Forks
- 71
- PR merge metrics
- No merged PRs in 30d
Description
# Exploration: Library-based Pattern Matching
I'm not sure how this fits in here, but with all the discussion about adding new syntax to support pattern matching (#337, #124, among others), I decided to do some tinkering to see how much could be done with the existing syntax and what we be the absolute minimum to get as many of the proposed pattern matching concepts working as possible.
## Examples
(I have a prototype where these actually run.)
```vb.net
Dim data As (x As Integer, y As Integer)
Do
Console.Write("Enter x: ")
data.x = CInt(Console.ReadLine())
Console.Write("Enter y: ")
data.y = CInt(Console.ReadLine())
Select Case data
Case Tuple(Value = 0, Value = 0)
Console.WriteLine("Origin")
Case Tuple(Value = 0, Anything)
Console.WriteLine("Y Axis")
Case Tuple(Anything, Value = 0)
Console.WriteLine("X Axis")
Case Tuple(Value > 0, Value > 0)
Console.WriteLine("Quadrant I")
Case Tuple(Value < 0, Value > 0)
Console.WriteLine("Quadrant II")
Case Tuple(Value < 0, Value < 0)
Console.WriteLine("Quadrant III")
Case Tuple(Value > 0, Value < 0)
Console.WriteLine("Quadrant IV")
End Select
Loop
```
```vb.net
Do
Dim data As New List(Of String)
Dim line As String
Do
Console.Write("Enter something:")
line = Console.ReadLine()
If line = "" Then
Exit Do
Else
data.Add(line)
End If
Loop
If data Like Enumerable(Match("A*"), Match("B*"), Match("C*"), Anything) Then
Console.WriteLine("Are you going through the letters of the alphabet?")
ElseIf data Like Enumerable(Match("*1"), Match("*2"), Match("*3"), Anything) Then
Console.WriteLine("These seem to be numbered")
Else
Console.WriteLine("Could find nothing")
End If
Loop
```
## How it works
### Pattern classes
There are a bunch of classes that implement an IPattern interface, overload the ```Like``` operator, and also overload the ```=``` operator (for ```Select Case``` support).
### Convenience factory methods
```Tuple(x, y)``` looks a little friendlier than ```New TuplePattern(x, y)```, so I implemented factory methods for most of the patterns I created so far.
This makes it simple to differentiate between a tuple pattern and a list/enumerable pattern, or between a constant string pattern (here called ```Value```), a regex string pattern, and a classic VB ```Like``` string pattern (here called ```Match```). *This is a proof-of-concept prototype, so the names are very much not final.*
All of these methods are kept in a ```Patterns``` module, actually using the fact that VB auto-imports module contents. (Most of the time, I wish VB didn't do that, but here I can see the point.)
The pattern that matches anything is a singleton object access through the ```Anything``` property.
### Comparison patterns using a "marker" object
There is no rule that says overloaded comparison operators need to return ```Boolean```.
The ```Value``` property is a singleton object of a ```ValueMarker``` class, whose overloaded comparison operators could return ```ComparisonPattern``` objects. The expression ```Value < 0``` could return the same object as ```New ComparisonPattern(0, Comparison.LessThan)```.
*Actually, in the current prototype, ```Value < 0``` returns ```New RangePattern(Integer.MinValue, 0, excludeStart:=False, excludeFinish:=True)```, but that's an implementation detail.*
Similarly, while my current prototype doesn't do this at the moment, it should be possible to overload the ```Not```, ```And```, and ```Or``` operators of each of the patterns to create more complex patterns.
### Type check patterns using generic type arguments
The function ```Type(Of T)()``` returns a ```New TypePattern(Of T)()``` which handles the type checking pattern. I already like
```vb.net
Select Case obj
Case Type(Of Foo)
'...
Case Type(Of Bar)
'...
Case Else
'...
End Select
```
a little more than
```vb.net
If TypeOf obj Is Foo Then
'...
ElseIf TypeOf obj Is Bar Then
'...
Else
'...
End If
```
### Not functional: Assignment patterns
If we go the factory-method route, the simplest-seeming way to implement variable-extracting patterns is using a ```ByRef``` parameter in the factory method/constructor. Instead of a variable pattern, we would have an assignment pattern. If (a big if these days, I know), VB ever got Out variables (#60), this would become a variable pattern without any additional work.
Why doesn't it work? Well, although the target is passed ```ByRef``` into the factory/constructor, there's no way to use that reference from the ```Like``` operator, since it's a completely separate method. Implementing this pattern using a ByRef-like type might work, but it sounds like that's off the table, too. (Not to mention, making this pattern ByRef-like means it couldn't implement an ```IPattern``` interface, which, in this prototype, all the composite patterns use behind the scenes.)
### Semi-functional: Nothing
```myData Like Nothing``` might not work. You can hack around it using ```CObj(myData)```, since the built-in ```Like``` handler works for ```Object``` (and ```String```, of course), and it does handle the ```Nothing``` case, but if your left-hand side is almost any other data type, ```Nothing``` won't help with the overload resolution, and you will likely get a compiler error.
The prototype also has some tricks to enable ```Nothing``` inside composite patterns.
## What it needs from the language (or what people can try to hack around)
The absolute minimum I would ask from the language team, if we could get it, would be the ability to at least use, if not create, ByRef-like types (#297), so we could try to implement the assignment pattern.
Second on the list would be Out variables (#60).
Third would be some sort of ```Case Like``` feature for ```Select Case```. The prototype gets ```Select Case``` working using the ```=``` operator, but I'd rather not enable ```=``` for the general case (the point is to steer people toward ```Like```), and implementing ```=``` requires also implementing ```<>```, which, again we don't need for pattern matching.
Beyond that, I could imagine LINQ-like syntax for creating these patterns and compiler optimizations that rewrite the pattern factory and ```Like``` operator into more straightforward code, like what C#'s pattern matching employs. I would also fit exhaustiveness checking and ```Select Case``` expressions into that imagined future.
## Wrapping up
I don't know if this wall of text is helpful to anyone--maybe it could help the community effort to kickstart VB advancement again, maybe it could be useful to Project Mercury--but I figured I'd push out these thoughts on how to stretch the existing VB language with new concepts as we look into the future.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.