Skip to content

Commit 21def26

Browse files
Update the docs for version 3.1.0
1 parent 82215ad commit 21def26

File tree

9 files changed

+271
-276
lines changed

9 files changed

+271
-276
lines changed

docs/articles/async.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,55 @@
11
# Asynchronous Pattern Matching
22

3-
Starting with version 3.0 asynchronous pattern matching is also available.
3+
Starting with version 3.0, asynchronous pattern matching is also available.
4+
5+
> [!IMPORTANT]
6+
> On .NET Standard 2.0, Matchmaker uses
7+
> [Microsoft.Bcl.AsyncInterfaces](https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces) as the polyfill for
8+
> asynchronous interfaces.
49
510
## Async Patterns
611

712
Async patterns are objects which implement the `Matchmaker.Patterns.Async.IAsyncPattern<TInput, TMatchResult>`
8-
interface. They are very similar to [normal patterns](patterns.md), except they are, well, matched asynchronously.
9-
The interface contains two members:
13+
interface. They are very similar to [normal patterns](patterns.md), except they are matched asynchronously. The
14+
interface contains two members:
1015

11-
```
16+
```c#
1217
string Description { get; }
1318

1419
Task<MatchResult<TMatchResult>> MatchAsync(Tinput input);
1520
```
1621

17-
The predefined patterns (contained in the `Matchmaker.Patterns.Async.AsyncPattern` class) and extension methods
18-
from `MatchMaker.Linq` are basically the same. There are also extensions for `Task<MatchResult<TMatchResult>>`.
22+
The predefined patterns (contained in the `Matchmaker.Patterns.Async.AsyncPattern` class) and extension methods from
23+
`MatchMaker.Linq` are basically the same. There are also extensions for `Task<MatchResult<TMatchResult>>`.
1924

2025
The only difference is that the `Cached` extension method returns a pattern which caches its inputs in a thread-safe
2126
manner.
2227

2328
Creating custom async patterns is also basically the same as creating custom patterns: you can use the `CreatePattern`
24-
methods from the `AsyncPattern` class, extend the
25-
`Matchmaker.Patterns.Async.AsyncPattern<TInput, TMatchResult>` class to get the `Description` property for
26-
free, or implement the `IAsyncPattern<TInput, TMatchResult>` directly (which is not recommended).
29+
methods from the `AsyncPattern` class, extend the `Matchmaker.Patterns.Async.AsyncPattern<TInput, TMatchResult>` class
30+
to get the `Description` property for free, or implement the `IAsyncPattern<TInput, TMatchResult>` directly.
2731

28-
Normal patterns can be turned into async patterns by calling the `AsAsync()` extension (defined in the
29-
`Matchmaker.Linq` namespace).
32+
Normal patterns can be turned into async patterns by calling the `AsAsync()` extension (defined in the `Matchmaker.Linq`
33+
namespace).
3034

3135
## Async Match Expressions
3236

3337
Async match expressions are also very similar to [normal match expressions](expressions.md). There are two types of
34-
async match expressions: `AsyncMatch<TInput, TOutput>` which yields a result and `AsyncMatch<TInput>` which
35-
doesn't. They can be created using methods in the `AsyncMatch` class.
38+
async match expressions: `AsyncMatch<TInput, TOutput>` which yields a result and `AsyncMatch<TInput>` which doesn't.
39+
They can be created using methods in the `AsyncMatch` class.
3640

37-
The `Case` methods of async match expressions are overloaded to take either async patterns or normal patterns (which
38-
are turned into async patterns using the `AsAsync()` extension) and to take either async or sync actions to executed
39-
when a pattern is matched successfully (sync actions are turned into pseudo-async actions).
41+
The `Case` methods of async match expressions are overloaded to take either async patterns or normal patterns (which are
42+
turned into async patterns using the `AsAsync()` extension) and to take either async or sync actions to executed when a
43+
pattern is matched successfully (sync actions are turned into async actions).
4044

4145
Async match expressions can be executed using the `ExecuteAsync`, `ExecuteNonStrictAsync` and
4246
`ExecuteWithFallthroughAsync` methods. The `ToFunction` method and its variations are also available.
43-
`ExecuteWithFallthroughAsync` returns an `IAsyncEnumerable` which enable lazy async execution of match
44-
expressions.
47+
`ExecuteWithFallthroughAsync` returns an `IAsyncEnumerable` which enable lazy async execution of match expressions.
4548

46-
The `Matchmaker.Linq` namespace contains the `EnumerateAsync` extension method for `IEnumerable<T>` which
49+
The `Matchmaker.Linq` namespace contains the `EnumerateAsync` extension method for `IAsyncEnumerable<T>` which
4750
enumerates it and ignores the result. You can use it if you just want to execute the match statement with fall-through.
4851

49-
Static async match expressions are also available. Use the `AsyncMatch.CreateStatic` methods to create them, just
50-
like normal match expressions. The methods accept an action on either `AsyncMatchBuilder<TInput, TOutput>` or
51-
`AsyncMatchBuilder<TInput>`. Static match expressions are globally cached and the caching process is thread-safe.
52-
Caches can be cleared with the `ClearCache` methods in `AsyncMatch`.
52+
Static async match expressions are also available. Use the `AsyncMatch.CreateStatic` methods to create them, just like
53+
normal match expressions. The methods accept an action on either `AsyncMatchBuilder<TInput, TOutput>` or
54+
`AsyncMatchBuilder<TInput>`. Static match expressions are globally cached and the caching process is thread-safe. Caches
55+
can be cleared with the `ClearCache` methods in `AsyncMatch`.

docs/articles/expressions.md

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Match Expressions
22

3-
The second central idea is the match expression itself. It is represented by two classes: `Match<TInput, TOutput>`
4-
and `Match<TInput>`. The difference between them is that the former represents a match expression which yields
5-
a result, and the latter represents a match expression which doesn't yield a result (also known as match statement).
3+
The second central idea is the match expression itself. It is represented by two classes: `Match<TInput, TOutput>` and
4+
`Match<TInput>`. The difference between them is that the former represents a match expression which yields a result, and
5+
the latter represents a match expression which doesn't yield a result (also known as a match statement).
66

77
## Using Match Expressions
88

@@ -12,27 +12,27 @@ A match expression can be created using the `Create` methods of the static class
1212

1313
### Adding Cases
1414

15-
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
17-
do not affect the ones on which they are called.
15+
The `Match` classes include `Case` methods which are used to add a pattern and a function which is executed if the match
16+
is successful. Match expressions are immutable `Case` methods return new match expressions; they do not affect the
17+
ones on which they are called.
1818

19-
`Case` methods are generic - they also contain information about the pattern's transformation type. Match expressions
19+
`Case` methods are generic they also contain information about the pattern's transformation type. Match expressions
2020
can contain patterns of arbitrary transformation types without knowing about these types.
2121

2222
### Executing Match Expressions
2323

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

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

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

3737
The `ToFunction` method and its variations are also available. They return a function which, when called, will execute
3838
the match expression.
@@ -45,7 +45,7 @@ Fall-through must be explicitly enabled for cases and then explicitly enabled du
4545
contain the `ExecuteWithFallthrough` method which takes fall-through behavior into account. `ExecuteOn` and
4646
`ExecuteStrict` ignore the fall-through behavior.
4747

48-
If a case has fall-through enabled, then the expression falls to the _next successful_ match, unlike `switch`, which
48+
If a case has fall-through enabled, then the expression falls to the next successful match, unlike `switch`, which
4949
falls to the next case whether it's successful or not.
5050

5151
The `Case` methods are overloaded to accept a boolean value which indicates the fall-through behavior. If fall-through
@@ -54,30 +54,30 @@ the expression will stop at this pattern and not go any further.
5454

5555
`Match.Create` is also overloaded to take the default fall-through behavior.
5656

57-
Matching with fall-through is lazy i.e. it returns an `IEnumerable` and is only executed when this enumerable
58-
is enumerated. Because matching will fall-through is lazy, it doesn't have any modes of execution - the user must
59-
decide whether to throw an exception or not if there were no successful matches.
57+
Matching with fall-through is lazy i.e. it returns an `IEnumerable` and is only executed when this enumerable is
58+
enumerated. Because matching will fall-through is lazy, it doesn't have any modes of execution the user must decide
59+
whether to throw an exception or not if there were no successful matches.
6060

61-
In the `Match<TInput, TOutput>` class the `ExecuteWithFallthrough` method returns an `IEnumerable<TOutput>`
62-
which can be used to get all successful match results.
61+
In the `Match<TInput, TOutput>` class, the `ExecuteWithFallthrough` method returns an `IEnumerable<TOutput>` which can
62+
be used to get all successful match results.
6363

64-
In the `Match<TInput>` class there are no results, so the `ExecuteWithFallthrough` method returns
65-
an `IEnumerable<object>` which should be used simply to enumerate the match process itself. This is implemented
66-
so that matching with fall-through is also lazy in this class. The values of the resulting enumerable don't matter -
67-
in fact, they are always `null`, because match statements don't produce any results. What matters is the process
68-
of enumeration.
64+
In the `Match<TInput>` class there are no results, so the `ExecuteWithFallthrough` method returns an
65+
`IEnumerable<object>` which should be used simply to enumerate the match process itself. This is implemented so that
66+
matching with fall-through is also lazy in this class. The values of the resulting enumerable don't matter - in fact,
67+
they are always `null`, because match statements don't produce any results. What matters is the process of enumeration.
6968

70-
You can use the LINQ's `Take` method to limit the number of executed matches, or the `Count` method to execute it
71-
and get the number of successful matches.
69+
You can use the LINQ's `Take` method to limit the number of executed matches, or the `Count` method to execute it and
70+
get the number of successful matches.
7271

73-
The `Matchmaker.Linq` namespace contains the `Enumerate` extension method for `IEnumerable<T>` which enumerates
74-
it and ignores the result. You can use it if you just want to execute the match statement with fall-through.
72+
The `Matchmaker.Linq` namespace contains the `Enumerate` extension method for `IEnumerable<T>` which enumerates it and
73+
ignores the result. You can use it if you just want to execute the match statement with fall-through.
7574

76-
**Remember: matching with fall-through is lazy and is actually executed when the result is enumerated.**
75+
> [!IMPORTANT]
76+
> Matching with fall-through is lazy and is actually executed when the result is enumerated.
7777
7878
Here's a (somewhat convoluted) implementation of the famous fizz-buzz program which uses matching with fall-through:
7979

80-
```
80+
```c#
8181
using System.Linq;
8282

8383
using Matchmaker;
@@ -99,7 +99,8 @@ var result = Enumerable.Range(0, 15)
9999
.Select(items => items.Aggregate(String.Concat))
100100
.ToList();
101101

102-
// The result is ("FizzBuzz", "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz");
102+
// The result is:
103+
// "FizzBuzz", "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"
103104
```
104105

105106
## Static Match Expressions
@@ -109,7 +110,7 @@ var result = Enumerable.Range(0, 15)
109110
One pain point of match expressions is that whenever a method which contains a match expression is executed, the match
110111
expression is initialized from scratch. Take a look at this example:
111112

112-
```
113+
```c#
113114
void DoStuff(int i) =>
114115
Match.Create<int, string>()
115116
.Case(...)
@@ -119,21 +120,21 @@ void DoStuff(int i) =>
119120
.ExecuteOn(i);
120121
```
121122

122-
The problem here is that if we call `DoStuff` 10,000 times, we will initialize the match expression 10,000 times
123-
as well, even though it's actually the same expression. Having just 4 cases may not seem like much, to the lag does
123+
The problem here is that if we call `DoStuff` 10,000 times, we will initialize the match expression 10,000 times as
124+
well, even though it's actually the same expression. Having just 4 cases may not seem like much, but the lag does
124125
accumulate if we execute it thousands of times.
125126

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

129130
### The Solution
130131

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

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

136-
```
137+
```c#
137138
void DoStuff(int i) =>
138139
Match.CreateStatic<int, string>(builder => builder
139140
.Case(...)
@@ -147,14 +148,14 @@ It looks almost the same, except for one difference: the calls to `Case` methods
147148
called the build action, which is passed to the `CreateStatic` method. Now this match expression will be initialized
148149
only once, and its initialization code is in the same place as its execution point.
149150

150-
The parameter of the build action has the type `MatchBuilder<TInput, TOutput` or `MatchBuilder<TInput>`
151-
depending on which type of match expressions you are building. This type has the same methods for adding cases as
152-
the `Match` classes and is mutable - the methods return the same builder instance.
151+
The parameter of the build action has the type `MatchBuilder<TInput, TOutput` or `MatchBuilder<TInput>`, depending on
152+
which type of match expressions you are building. This type has the same methods for adding cases as the `Match` classes
153+
and is mutable the methods return the same builder instance.
153154

154155
`MatchBuilder` also has the `Fallthrough` method which specifies the default fall-through behavior. But this method
155156
specifies fall-through behavior only for cases that are defined after it. For example:
156157

157-
```
158+
```c#
158159
builder
159160
.Fallthrough(true)
160161
.Case(...) // this case has fall-through behavior if not specified otherwise
@@ -168,14 +169,14 @@ Every case can configure its fall-through behavior individually as well.
168169

169170
### Caching Match Expressions
170171

171-
The build action will be called only once, and its result will be cached. The cache is a static hash-table.
172-
The caching process is not thread-safe.
172+
The build action will be called only once, and its result will be cached. The cache is a static hash-table. The caching
173+
process is not thread-safe.
173174

174175
The key of the cache is the place where the `CreateStatic` method is called. Apart from the build action, this method
175-
also accepts two caller info arguments: the path to the source file and the line in the source file. Users don't
176-
need to pass these arguments to the method as they have the `CallerFilePath` and `CallerLineNumber` attributes.
176+
also accepts two caller info arguments: the path to the source file and the line in the source file. Users don't need to
177+
pass these arguments to the method as they have the `CallerFilePath` and `CallerLineNumber` attributes.
177178

178-
The `Match` class also contains the `ClearCache` methods which clear a global cache. Match expressions have a cache
179-
per type (so `Match<int, int>` uses a different cache than `Match<int, string>`) so `ClearCache` only clears one
180-
cache. Clearing the cache will force all static match expressions of that type to be reinitialized. This process is
181-
not thread-safe as well.
179+
The `Match` class also contains the `ClearCache` methods which clear a global cache. Match expressions have a cache per
180+
type (so `Match<int, int>` uses a different cache than `Match<int, string>`) so `ClearCache` only clears one cache.
181+
Clearing the cache will force all static match expressions of that type to be reinitialized. This process is not
182+
thread-safe as well.

0 commit comments

Comments
 (0)