Description
Some people have suggested to me that pattern matching doesn't feel like a VB feature. What they mean is "Pattern matching sounds like some advanced programming stuff". I disagree. I think pattern matching is very much so a VB feature. In fact, I suggest that most VB programmers, myself included, have spent most of their careers looking at data--be it DB records, or string input, or messages from one device or another--and testing the shape of that data against known patterns, separating structure from content, and extracting select content to fit our needs. That's what every use of the Like operator, the InStr function, and most If
' and Select
statements are really doing. They're just going about it in a rather tedious (imperative) way. Pattern Matching is a powerful feature we can add to VB to make the same kinds of tasks we've always been doing much more concise, readable, and declarative.
I propose we extend existing Case
statements to support a new kind of clause, the Match
or Matches
clause (depending on your grammatical proclivities) of the form:
Case Match
pattern [When
expression]
Where pattern is one of:
The wildcard pattern
*
Matches all values, including null.
The variable pattern
identifier [?
] [As
typename]
- Declares a new variable with name identifier.
- If no type is specified will match any non-null value.
- If a type is specified the value much be of that type.
- If the
?
modifier is used will match null values but will still fail if the value is a non-null value of another type than specified. - Type of the variable is either the specified type is provided, or inferred from the value being matched if no type is provided, or nullable version in either case if the
?
modifier is used.
The function pattern
expression (
[ pattern1 [,
pattern2, ...] ] )
- Matches if the function resolved from evaluating expression returns true. This function may optionally provided one or more outputs, each of which is recursively matched against the corresponding specified pattern.
Example:
Select Case "1"
Case Integer.TryParse(value) When value > 0
End Select
Order of execution in the above example is as follows:
Integer.TryParse
is called passing the value of theSelect Case
statement in as its first argument, a new variable named 'value' of the type of the second argument of theTryParse
method is passed in as the second argument (which is ByRef).- If the invocation of
TryParse
returns true, execution passes to theWhen
clause. The expressionvalue > 0
is evaluated as true. - Execution then proceeds into the
Case
block.
The tuple pattern
(
pattern1 [,
pattern2, ...] )
- Matches a tuple of an arity equal to the number of patterns specified. Recursively matches each element of the tuple against the corresponding pattern.
However, the list doesn't end here. In fact, it's my belief that the tuple pattern is just the first example of a new trend in the language that with each new expression we add for constructing an object, there is a corresponding pattern for decomposing that object that mirrors the construction syntax. For example, one can imagine (and I have) patterns based on decomposing arrays based on the array literal syntax, decomposing strings based on the string interpolation syntax, and decomposing XML fragments based on the XML literal syntax. The JSON literal proposal (#101) also demonstrates this.
The entire Match
(or Matches
) clause succeeds if the specified pattern succeeds AND the expression provided in the When
clause (if provided) evaluates as true. The expression may refer to variables introduced in pattern.