A while ago @Michael_Ilseman posted a document discussing future directions for String
. This document includes a sketch for generalized pattern matching (here: State of String: ABI, Performance, Ergonomics, and You! · GitHub). I would like to start a discussion focused specifically on this topic.
The design in the string update document consists of the following protocol:
protocol Pattern {
associatedtype In
associatedtype Out
func match(_: In) -> Out?
}
as well as the following usage for user-defined patterns:
let myValue: T = ...
let pattern: MyTPattern<(U,U)> = ... // matches a T to (U, U)
let otherPattern: OtherTPattern<V> = ... // matches a T to V
switch myValue {
case (let a: Int, let b: Int) <- pattern: ...
case let pair <- pattern: ... // pair has type (U,U)
case let d: Double <- otherPattern: ...
case let num <- otherPattern: // num has type V
}
There is a lot to like about this design. In particular, patterns can be stored in variables. They are first class entities in the langauge.
There are two ideas that I started thinking about when reading this design. First, unfortunately this design does not allow users to define a set patterns that exhaustively matches a given type. I think it would be useful to discuss what a design that does support exhaustiveness might look like.
Second, perhaps we could support a new form of dot shorthand to allow user-defined patterns to be matched using the same syntax as enum cases. Suppose we have the following extension on MyTPattern
from the preceding example:
extension MyTPattern {
static var twoInts: MyTPattern<(Int, Int)> { ... }
}
This pattern declaration along with a dot shorthand might allow us to write a switch using this syntax:
switch myValue {
case .twoInts(let int1, let int2): ...
// other patterns
}
The idea here is that the case statement creates a type context that expects a pattern matching T
. Static members of types that conform to Pattern where In == T
would be available for use. The more general syntactic form supporting patterns as variables would also be available.
An alternative approach might be for dot shorthand to look for static members of T
that return a type conforming to Pattern where In == T
. This alternative might help implementation by scoping lookup to static members of T
rather than all types X: Pattern where In == T
.
I am interested in hearing what the community thinks about these ideas in particular and user-defined patterns in general.