Skip to content

Commit 580920c

Browse files
Finish updating the documentation
1 parent 44b34a6 commit 580920c

File tree

11 files changed

+303
-88
lines changed

11 files changed

+303
-88
lines changed

CHANGELOG.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,21 @@ What's new in version 2.0 (almost all changes are breaking):
99
- Dropped the dependency on [language-ext](https://github.com/louthy/language-ext)
1010
- Completely updated the pattern hierarchy and built-in patterns
1111
- The deprecated `StructNull` pattern is removed
12-
- Matching with fallthrough became lazy
13-
- Strict matching with fallthrough was removed
12+
- Matching with fall-through became lazy
13+
- Strict matching with fall-through was removed
1414
- Descriptions were added to patterns
15-
- Creating custom patterns became possible through factory methods
16-
and extension methods
15+
- Creating custom patterns became possible through factory methods and extension methods
1716
- The default mode of match statements changed from non-strict to strict
1817

18+
Read the [migration guide](https://tolikpylypchuk.github.io/Matchmaker/v2.0.0/articles/migration.html) for more info.
19+
1920
## v1.2
2021

2122
What's new in version 1.2:
2223

2324
- Added tests
2425
- Deprecated the `StructNull` pattern in favour of `ValueNull`
25-
- Fixed a bug which made strict matching with fallthrough unusable
26+
- Fixed a bug which made strict matching with fall-through unusable
2627
- Fixed null handling in some predefined patterns
2728
- Minor code refactoring
2829

@@ -33,7 +34,7 @@ What's new in version 1.1:
3334
- `Matcher` classes renamed to `Match` (breaking change).
3435
- `OptionUnsafe` is now used instead of `Option` in patterns to fully support `null` values (breaking change).
3536
- `ExecuteOnStrict` in `Match<TInput>` renamed to `ExecuteStrict` (breaking change).
36-
- Implemented matching with fallthrough
37+
- Implemented matching with fall-through
3738
- Added two new patterns - `Null` for classes and `StructNull` for nullable structs.
3839

3940
Although there are several breaking changes, the major version is not incremented, as these changes

Matchmaker/MatchException.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public MatchException()
2222
/// Initializes a new instance of the <see cref="MatchException" /> class.
2323
/// </summary>
2424
/// <param name="message">The message which describes this exception.</param>
25-
public MatchException(string message) : base(message)
25+
public MatchException(string message)
26+
: base(message)
2627
{ }
2728

2829
/// <summary>

README.md

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
# Matchmaker
22

3+
[![NuGet](https://img.shields.io/nuget/v/Matchmaker.svg)](https://www.nuget.org/packages/Matchmaker/)
34
[![Build status](https://ci.appveyor.com/api/projects/status/wptuo5d5mi4blss0?svg=true)](https://ci.appveyor.com/project/TolikPylypchuk/matchmaker)
45

5-
A library which enables more powerful pattern matching
6-
than is currently available in the C#'s `switch` statement/expression.
6+
A library which enables more powerful pattern matching than is currently available in the C#'s `switch`
7+
statement/expression.
78

8-
This library is a successor of
9-
[PatternMatching](https://github.com/TolikPylypchuk/PatternMatching).
9+
This library is a successor of [PatternMatching](https://github.com/TolikPylypchuk/PatternMatching).
1010
Version 1.x can be found there. This repository contains version 2+.
1111

1212
## Installation
1313

14-
This library cannot be installed through NuGet until version 2.0 is released.
15-
For now you can install the [older version](https://www.nuget.org/packages/CSharpStuff.PatternMatching/).
14+
```
15+
Install-Package Matchmaker -Version 2.0.0
16+
```
1617

17-
## A simple example
18+
## A Simple Example
1819

1920
This is what the simplest match expression looks like:
2021

@@ -61,33 +62,59 @@ switch (i)
6162
}
6263
```
6364

64-
While this example doesn't show the full power of pattern matching, there are
65-
a few things to note here:
65+
While this example doesn't show the full power of pattern matching, there are a few things to note here:
6666

67-
- The match expression yields a result. We don't have to assign the result
68-
explicitly in each case.
67+
- The match expression yields a result. We don't have to assign the result explicitly in each case.
6968

70-
- The input of the match expression is specified _after_ all the cases. This
71-
allows us to save the match expression in an object, and use it multiple times
72-
on different input values.
69+
- The input of the match expression is specified _after_ all the cases. This allows us to save the match expression
70+
in an object, and use it multiple times on different input values.
7371

74-
- The default case is a pattern, just like any other. It's called `Any` and
75-
is always matched successfully.
72+
- The default case is a pattern, just like any other. It's called `Any` and is always matched successfully.
7673

77-
- Like in `switch` the patterns are tried out sequentially. This means that
78-
the `Any` pattern should always come last.
74+
- Like in `switch` the patterns are tried out sequentially. This means that the `Any` pattern should always
75+
come last.
7976

80-
The release C# 8.0 included a new way to write switch expressions which yield a value.
81-
While this drastically reduced the need for external libraries like this one
82-
for pattern matching, the language itself includes only the simplest patterns.
83-
This library lets the user define arbitrary patterns, which makes this library
84-
more powerful than the switch expressions.
77+
The release C# 8.0 included a new way to write `switch` expressions which yield a value. While this drastically reduced
78+
the need for external libraries like this one for pattern matching, the language itself includes only the simplest
79+
patterns. This library lets the user define arbitrary patterns, which makes this library more powerful than the
80+
`switch` expressions.
81+
82+
Here's what the equivalent switch expression looks like in C# 8.0:
83+
84+
```
85+
int i = 5;
86+
87+
string result = i switch
88+
{
89+
1 => "one",
90+
2 => "two",
91+
3 => "three",
92+
4 => "four",
93+
_ => i.ToString()
94+
};
95+
```
96+
97+
OK, this is much shorter and cleaner than the previous two examples. But this library shines when the patterns are
98+
more complex. C# allows only constant patterns, type patterns, and `when` expressions. This library allows anything
99+
you can think about.
85100

86101
## More Info
87102

103+
If you want to learn how to use this library, you should read the
104+
[documentation](https://tolikpylypchuk.github.io/Matchmaker/v2.0.0). The articles provide everything you need to know
105+
to use this library.
106+
107+
If you need extensive information, go to the
108+
[API reference](https://tolikpylypchuk.github.io/Matchmaker/v2.0.0/api/index.html).
109+
110+
If you need even more info about this library, you can go through the
111+
[tests](https://github.com/TolikPylypchuk/Matchmaker/tree/v2.0.0/Matchmaker.Tests). They are property-based and as such
112+
they describe every aspect of the classes and their members.
113+
88114
The documentation can be found here:
89115

90116
- Version 2.0.0: https://tolikpylypchuk.github.io/Matchmaker/v2.0.0
117+
- Older versions: https://github.com/TolikPylypchuk/PatternMatching
91118

92119
## License
93120

docs/articles/expressions.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Match Expressions
1+
# Match Expressions
22

33
The second central idea is the match expression itself. It is represented by two classes: `Match<TInput, TOutput>`
44
and `Match<TInput>`. The difference between them is that the former represents a match expression which yields
@@ -13,7 +13,7 @@ A match expression can be created using the `Create` methods of the static class
1313
### Adding Cases
1414

1515
The `Match` classes include `Case` methods which are used to add a pattern and a function which is executed if
16-
the match is successful. Match expressions are immutable - `Case` methods return new match expressions, they
16+
the match is successful. Match expressions are immutable - `Case` methods return new match expressions; they
1717
do not affect the ones on which they are called.
1818

1919
`Case` methods are generic - they also contain information about the pattern's transformation type. Match expressions
@@ -24,23 +24,24 @@ expressions.
2424
### Executing Match Expressions
2525

2626
To execute a match expression, the `ExecuteOn` method is used. It takes the input value to match. There are two modes
27-
of execution in match expressions: strict and non-strict. The strict mode throws an exception and the non-strict doesn't.
27+
of execution in match expressions: strict and non-strict. The strict mode throws an exception if no matches were found,
28+
and the non-strict doesn't.
2829

29-
In the `Match<TInput, TOutput>` class the `ExecuteOn` method returns the result of the match, or throws a
30+
In the `Match<TInput, TOutput>` class the `ExecuteOn` method returns the result of the match or throws a
3031
`MatchException` if no successful match was found. `Match<TInput, TOutput>` also contains the `ExecuteNonStrict`
31-
method which executes the match expression in the non-strict mode. It returns `MatchResult<TOutput>`, because
32+
method which executes the match expression in the non-strict mode. It returns `MatchResult<TOutput>` because
3233
the result might not be present.
3334

34-
In the `Match<TInput>` class the `ExecuteOn` method doesn't return anyhting, and also throws the `MatchException`
35+
In the `Match<TInput>` class the `ExecuteOn` method doesn't return anything, and also throws a `MatchException`
3536
if the match wasn't successful. This class also contains the `ExecuteNonStrict` method - it returns a boolean value
36-
which indicates whether the match was successful, and doesn't throw an exception if it wasn't.
37+
which indicates whether the match was successful and doesn't throw an exception if it wasn't.
3738

3839
The `ToFunction` method and its variations are also available. They return a function which, when called, will execute
3940
the match expression.
4041

4142
## Matching with Fall-through
4243

43-
C, C++ and Java support fall-through in `switch` expressions. So does this library, although it works differently here.
44+
C, C++ and, Java support fall-through in `switch` statements. So does this library, although it works differently here.
4445

4546
Fall-through must be explicitly enabled for cases and then explicitly enabled during execution. Both `Match` classes
4647
contain the `ExecuteWithFallthrough` method which takes fall-through behavior into account. `ExecuteOn` and
@@ -49,16 +50,16 @@ contain the `ExecuteWithFallthrough` method which takes fall-through behavior in
4950
If a case has fall-through enabled, then the expression falls to the _next successful_ match, unlike `switch`, which
5051
falls to the next case whether it's successful or not.
5152

52-
Matching with fall-through is lazy i.e. it returns an `IEnumerable` and is only executed when this enumerable
53-
is enumerated. Because matching will fall-through is lazy, it doesn't have any modes of execution - the user must
54-
decide whether to throw exceptions or not if there were no successful matches.
55-
5653
The `Case` methods are overloaded to accept a boolean value which indicates the fall-through behavior. If fall-through
5754
is enabled for a pattern, then the expression will continue searching for the next successful pattern. If it isn't, then
5855
the expression will stop at this pattern and not go any further.
5956

6057
`Match.Create` is also overloaded to take the default fall-through behavior.
6158

59+
Matching with fall-through is lazy i.e. it returns an `IEnumerable` and is only executed when this enumerable
60+
is enumerated. Because matching will fall-through is lazy, it doesn't have any modes of execution - the user must
61+
decide whether to throw an exception or not if there were no successful matches.
62+
6263
In the `Match<TInput, TOutput>` class the `ExecuteWithFallthrough` method returns an `IEnumerable<TOutput>`
6364
which can be used to get all successful match results.
6465

@@ -76,7 +77,7 @@ it and ignores the result. You can use it if you just want to execute the match
7677

7778
**Remember: matching with fall-through is lazy and is actually executed when the result is enumerated.**
7879

79-
Here's a (somewhat convulted) implementation of the famous fizz-buzz program which uses matching with fall-through:
80+
Here's a (somewhat convoluted) implementation of the famous fizz-buzz program which uses matching with fall-through:
8081

8182
```
8283
using System.Linq;
@@ -107,8 +108,8 @@ var result = Enumerable.Range(0, 15)
107108

108109
### The Initialization Problem
109110

110-
One pain point of match expressions is that wherever a method which contains a match expression is executed, the match
111-
expression is initialized from scratch. Take a look at the example:
111+
One pain point of match expressions is that whenever a method which contains a match expression is executed, the match
112+
expression is initialized from scratch. Take a look at this example:
112113

113114
```
114115
void DoStuff(int i)
@@ -125,14 +126,14 @@ as well, even though it's actually the same expression. Having just 4 cases may
125126
accumulate if we execute it thousands of times.
126127

127128
We can save the expression in a field and then call the `ExecuteOn` method on this field. But this makes the code
128-
much less readable, because the case definitions are in a different place from the actual execution point.
129+
much less readable because the case definitions are in a different place from the actual execution point.
129130

130131
### The Solution
131132

132133
There is a way to create 'static match expressions' - expressions which will be initialized only once.
133134

134-
The `Match` class contains `CreateStatic` methods which allow the creation of static match expressions. Take a look
135-
at the modified example.
135+
The `Match` class contains the `CreateStatic` methods which allow the creation of static match expressions.
136+
Take a look at the modified example:
136137

137138
```
138139
void DoStuff(int i)
@@ -144,9 +145,9 @@ void DoStuff(int i)
144145
.ExecuteOn(i);
145146
```
146147

147-
It looks almost the same, except for one difference: he calls to `Case` methods are inside the lambda expression,
148-
called the build action, which is passed to the `CreateStatic` method. Now this match expressions will be initialized
149-
only once and its initialization code is in the same place as its execution point.
148+
It looks almost the same, except for one difference: the calls to `Case` methods are inside the lambda expression,
149+
called the build action, which is passed to the `CreateStatic` method. Now this match expression will be initialized
150+
only once, and its initialization code is in the same place as its execution point.
150151

151152
The parameter of the build action has the type `MatchBuilder<TInput, TOutput` or `MatchBuilder<TInput>`
152153
depending on which type of match expressions you are building. This type has the same methods for adding cases as

docs/articles/intro.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,24 @@ you can think about.
8282

8383
## Performance
8484

85-
Versions 1.x used the DLR to provide type-safe pattern matching on any types
86-
without having to remember all those types. Thus the performance was _much_
87-
worse than C#'s switch statements/expressions (even though I didn't perform
88-
any benchmarks).
89-
90-
Versions 2+ of this library don't use the DLR anymore - I've found a better way
91-
to do this, and frankly, I'm amazed I didn't think of this way before. So I'm
92-
guessing the performance of the new versions must be much better than versions 1.x.
93-
Maybe, I'll even implement some benchmarks in the future to compare the performance
94-
of this library in comparison to the switch statements/expressions.
85+
Versions 1.x used the DLR to provide type-safe pattern matching on any types without having to remember all those types.
86+
Thus, the performance was _much_ worse than C#'s switch statements/expressions (even though I didn't perform any
87+
benchmarks).
88+
89+
Versions 2+ of this library don't use the DLR anymore - I've found a better way to do this, and frankly, I'm amazed I
90+
didn't think of this way before. So, I'm guessing the performance of the new versions must be much better than versions
91+
1.x.
92+
93+
## More Info
94+
95+
If you want to learn how to use this library, you should read these articles. They provide everything you need to know
96+
to use this library.
97+
98+
If you need extensive information, go to the [API reference](../api/index.md).
99+
100+
If you need even more info about this library, you can go through the
101+
[tests](https://github.com/TolikPylypchuk/Matchmaker/tree/v2.0.0/Matchmaker.Tests). They are property-based and as such
102+
they describe every aspect of the classes and their members. They cover 100% of this library's code (except
103+
the `MatchException` class which is trivial).
95104

96105
Next article: [Match results](results.md).

docs/articles/migration.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,63 @@
11
# Migration Guide
22

3+
This article describes how to migrate to version 2.0.0 from
4+
[PatternMatching v1.2.0](https://github.com/TolikPylypchuk/PatternMatching).
5+
6+
If you need to migrate from older versions, first migrate to version 1.2.0. You can do that just by reading the
7+
changelog, because previous versions contained much fewer changes and it's much simpler to migrate.
8+
9+
## General
10+
11+
Since this library has a new name, the namespace is different as well. Instead of the `PatternMatching` namespace
12+
there are three namespaces: `Matchmaker`, `Matchmaker.Patterns` and `Matchmaker.Linq`.
13+
14+
The dependency on [language-ext](https://github.com/louthy/language-ext) was dropped. Instead of using `OptionUnsafe`
15+
this library now uses its own `MatchResult`.
16+
17+
## Patterns
18+
19+
The predefined patterns haven't changed much, but the way to create custom patterns changed drastically.
20+
21+
The `Match` method in `IPattern<TInput, TMatchResult>` now returns `MatchResult<TMatchResult>` instead of
22+
`OptionUnsafe<TMatchResult>`.
23+
24+
The `IPattern<TInput, TMatchResult>` now contains the `Description` property. If you implemented this interface,
25+
you can add it and make it return an empty string if you don't want a description.
26+
27+
`IPattern<TInput, TMatchResult>` now extends `IPattern<TInput>`. If you implemented this interface, it's better
28+
to extend the new `Pattern<TInput, TMatchResult>` class instead, as it provides both an implementation of the less
29+
generic interface, and the `Description` property.
30+
31+
The `ConditionalPattern<TInput, TMatchResult, TPattern>` is gone. It's too much work for the users to implement
32+
filtering of patterns if they want a highly customized pattern. If you filtered pattern results with the `When` method
33+
before, now you can do that using the `Where` extension method from the `Matchmaker.Linq` namespace, which works on
34+
all patterns, and doesn't need a special base class. I renamed this method because previously I wanted it to look like
35+
the `when` clause of the `switch` expressions, but now this method is part of LINQ to Patterns, so `Where` is more
36+
appropriate.
37+
38+
`SimplePattern<TInput>` is gone and `Pattern<TInput, TMatchResult>` now serves as a base class for patterns.
39+
If you need to create a pattern from a function or a predicate, use the `CreatePattern` methods in the `Pattern`
40+
class.
41+
42+
Since `SimplePattern<TInput>` is gone, you cannot use operators to compose patterns (`&`, `|` and `^`). Also,
43+
the `And`, `Or` and `Xor` methods are not part of pattern definition - they are extension methods from the
44+
`Matchmaker.Linq` namespace. The `~` operator is gone as well. Use `Not` instead.
45+
46+
The `StructNull` pattern is gone. It was deprecated in version 1.2.0. The `ValueNull` pattern provides the same
47+
functionality.
48+
49+
## Match Expressions
50+
51+
The default mode of execution for match statements is now strict. So `ExecuteOn` is strict. The `ExecuteStrict`
52+
method is gone and `ExecuteNonStrict` is added. This was changed because it was weird to have different default modes
53+
in match expressions and match statements.
54+
55+
Matching with fall-through became lazy. This is major change. The result in match expressions is now not the `Lst`
56+
from language-ext, but a lazy `IEnumerable` which the user has to enumerate for the match to actually be executed.
57+
Match statements also return an `IEnumerable` instead of a number of successful cases. If you want to know the number
58+
of successful cases, you can call `Count()` on the result of the match. Or you can call `Enumerate` from
59+
`Matchmaker.Linq` if you just want to execute it. Since matching with fall-though is lazy, it doesn't have modes
60+
of execution - it's just non-strict. The library cannot decide to throw an exception if there are no successful cases
61+
because the library doesn't decide when to execute the expression.
62+
363
Next article: [Why this library was written](why.md)

0 commit comments

Comments
 (0)