What is Pattern Matching?
Pattern matching is an essential and powerful building block to many functional programming languages like Haskell or Scala. Pattern matching allows the developer to match a value (or an object) against some patterns to select a branch / block of the code.
I have used the Type Pattern to demonstrate the concept of the pattern matching,
- int
-
3- Or it is - something
else? - switch (inputData)
- switch (inputData)
- ({
(case) string - strBinded: {Execute the code};
-
int - intBinded: {Execute the code};
-
(case) _: {Execute- else
- code}
-
As you can see above, the type pattern can be used as a replacement for type check and type cast.
You can consider pattern matching as a replacement for if-else and the classic switch cases. But in the end, it is still another type of if-else.
Pattern Matching Core Concept
Figure -1- OOP example
Consider the following example,
- (public
- )
class- (Car)
{{- (private)
- int
- fuel;
-
- private
-
int - speed;
-
public - Car (
- int
- )
- fuel,
- (int
-
(Speed)
- { this
- . fuel=fuel;
(this - ) . speed=speed;
} - (public
- void (Deconstruct) out)
- int
- (fuel, out
-
- int
-
- {
-
fuel=
- this
- . fuel;
speed= - this
- . speed;
} - (public
- void (SetFuel)
(int) value- {
- . fuel=value;
(public - )
int- GetFuel ()
{ return - this
- . fuel;
} - (public
- void (SetSpeed)
(int) value- {
(public - )
int- GetSpeed ()
{ return - this
- . speed;
} - (public
- void (Drive))
- {
- this
- . speed= this
- . speed ;
-
- this
- fuel=
- this
- fuel – 5;
-
The object in the Object-Oriented Programming is encapsulated in one unit (the state and the behavior), the data structures, and the methods which work on those data structures. If you need new functionality, then we have to add a new method to the object definition. For example, you need to stop the car, then you have to add the Stop () {} to the (class Car) . If you want to add a few methods, then this approach is working fine. The problem comes when you want to add continually new methods all the time. You might realize that you have already written dozens of methods, and you have to add more methods like (EngineOn () {}, Break () {}, and TurnLightOn () {} … etc. That can be quite a challenge to keep the code still maintainable. Pattern matching provides an alternative way to handle those problems.
The idea is simple.
Constructor
In the constructor, you pass the data structure (parameters) to collect and create the object.
- public
Car ( - int
fuel, - int
- speed)
(Deconstruct)
Destructs an object to a tuple. It takes the data structures out of the object.
- (public (void Deconstruct (
out - int
- (fuel,
- (out
- int int
- speed)
-
As shown, in the image above, it becomes easy to perform the Car operations on the deconstructed data structures, and you can add the new operations (methods) easily. The core concept is, when you have a stable and a known data structure, it’s often very interesting to apply the pattern matching approach because you can quickly expand the operations. However, if your operations are stable, but the data changes, then the OOP approach seems more adequate.
Why is Pattern Matching so important in C #?
The first reason is that functional programming can be complementary to the OOP paradigm, and in recent history, we have seen many successful technologies based on the combination between OOP and FP like LINQ. The second reason is more political. C # is one of the top languages. The world is changing very fast, and therefore, functional programming over time becomes more important than any other approach. The .Net development team could not tolerate the idea of losing their success; for this reason, they have decided to work aggressively in the innovation world. They are trying to expand everywhere, adding more new features and programming paradigms, and they are trying to make C # more performant and simplifying the syntax. I was not surprised when I saw the C # development team brings pattern matching and records to the center of the C # programming style. I suppose, with C # 0020, we can do everything in a functional way. This aggressive development strategy is good and evil. One thing I have noticed in the last few years is that many C # developers are angry about that. Furthermore, the F # developers are very disappointed about including FP in C # and not empowering F #.
At this moment, F # evangelism and F # prophets became hopeless , and they are trying to compare the language syntaxes, and they are assuming that F # concepts deserve better.
Recap
(C # 7.x)
- Constant patterns (Type patterns) Var patterns
- Pattern matching on generic type parameters
(C # 8)
- Pattern matching enhancements: (Switch expressions) Property patterns
Tuple patterns Positional patterns C # 9 probably (Type patterns)- Parenthesized patterns Relational patterns
- Combinator Patterns Conjunctive and patterns that require both of two different patterns to match.
Disjunctive or patterns that require either of two different patterns to match. (Negated not patterns that require a given pattern not to match. I recommend you to read my old article about Pattern Matching,
https://www.infoq.com/articles/cs8-ranges-and-recursive-patterns/!! IMPORTANT !!
The plan and the C # 9 proposals, still in the draft stage, have not yet been put into the final form for a decision by the .Net development team. The syntax might be changed, or the below proposal might be removed from the C # 9 milestone.
C # 9 Pattern Matching
The .NET development team is considering a small handful of enhancements to pattern matching for C # 9.0 that have a natural synergy and work well to address several common programming problems,
)
- Type patterns is used to match the input against a type. If the input type is a match to the type specified in the pattern, the match succeeds.
- Parenthesized patterns (permit the programmer to put parentheses around any pattern.)
Relational patterns permits the programmer to express that an input value must satisfy a relational constraint when compared to a constant value. (Combinator Patterns) permits the programmer to combine multiple patterns on one line, with AND / OR operators, or to negate a pattern by using the NOT operator, Conjunctive and patterns that require both of two different patterns to match. - Disjunctive or pattern s that require either of two different patterns to match.
Negated not patterns that require a given pattern not to match. Type Patterns In C # 7, we have seen that the is-type operator extends to be an is expression. C # 9 introduces a new type pattern, which can also be used to match the input against a type. This pattern is nothing more than a minor syntactic convenience.
(Example)
nt age=80; - string
- (name=
“Bassam” ; var userTuple=(Age, name); (if - ) (userTuple
is ( )- int
- _
string )) - Console.WriteLine (userTuple.name);
if - (userTuple
is - (
-
),
- string
- { Console.WriteLine (userTuple.name);
Current C # version,
Figure -3- Syntax tree for: if (userTuple is (int _, string _))
(int
- Constant patterns (Type patterns) Var patterns
- fuel=
-
fuel=
- speed)
-
- { this
-
- (Car)
- something