
C# Pattern Matching - brudgers
https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching
======
S_A_P
Resharper has proven to be a great way for me to start learning and
integrating new language features. I code in my original style and resharper
suggests changes based on new features like pattern matching. At first I didnt
see the benefit, but this is a hugely powerful feature once you start to wrap
your mind around it.

~~~
keithnz
as an aside, if you got Rider as part of your resharper subscription, try it
out, it is basically a drop in replacement for visual studio but faster and
with many many little quality of life improvements you never knew you needed
:)

~~~
qwerty456127
> replacement for visual studio but faster

How can a IntelliJ Idea derivative written in Java be faster than VistalStudio
which is native code? Both Idea and PyCharm work much slower than VisualStudio
on my machine.

~~~
eberkund
Because VS has limitations on the amount of memory it can use and although
they have been working on this, there is still functionality which is highly
single threaded whereas Rider tends to offload most of the functionality from
the UI thread into background processes.

~~~
eyegor
The memory limitations can be partially kicked down the road by setting
/largeaddressaware on devenv.exe. Ofc it's still beyond frustrating when you
have a large solution with many component projects. I personally ram against
the 4gb ceiling constantly.

------
eyegor
Heads up for C# devs, you should switch all your code bases to use (x is null)
and !(x is null) instead of ==. The is operator can't be overloaded, and
always compiles to IL eq, whereas == can be overloaded in custom types. Of
course it would also be nice if everything was moved to nullable reference
types [0], but that's a non trivial amount of work. Note that most C#8
features can be enabled manually through the csproj files, including nullable
reference types, even if you're using framework.

[0] [https://docs.microsoft.com/en-us/dotnet/csharp/nullable-
refe...](https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references)

~~~
sedatk
C# compiler doesn’t regard “x is object” or “x is null” as null checking
statements, so you get warnings if you’re using nullable references.

Also, I don’t understand the scare over operator overloading. It’s not common
and it works fine with nulls too as long as it’s implemented correctly. If
it’s buggy, you’re screwed for other cases anyway, it isn’t much helpful to
try to fix null checks only.

I find this advice overhyped because of these reasons.

~~~
BoorishBears
Unity used to take advantage of overloading to implement null checking with
"sentinel values" representing a non-existent reference in the Editor

I found this post explaining they considered moving away from the pattern, but
I'm not sure if they followed through:

[https://blogs.unity3d.com/2014/05/16/custom-operator-
should-...](https://blogs.unity3d.com/2014/05/16/custom-operator-should-we-
keep-it/?_ga=2.39545259.946914061.1580882722-813850683.1580882722)

~~~
marijnz
They didn't move away from the pattern and can't anymore as it would break
almost every existing Unity project.

------
kag0
I wrote up how I'd do this in scala, just to compare and contrast

    
    
        val shape: Option[Shape] = ???
        shape.map {
          case Square(0) | Circle(0)               => 0
          case Triangle(b, h)  if b == 0 || h == 0 => 0
          case Rectangle(l, h) if l == 0 || h == 0 => 0
    
          case Square(side)              => side * side
          case Circle(radius)            => radius * radius * math.Pi
          case Triangle(base, height)    => base * height / 2
          case Rectangle(length, height) => length * height
        }
    

what I noticed

    
    
      * scala doesn't have a way for cases to fall through, so the first cases have to each declare that the result is 0. it would be cool if we could use something in place of '=>' to make the case fall through.  
      * C# doesn't have structural matching, so the 'when' keyword is used more often.  
      * scala's pattern matching is exhaustive so if we assume the shapes are in a sealed type hierarchy then we don't need a default case.   
      * it's idiomatic to use 'Option' instead of null in scala, but there are lots of libraries in c# that offer option monads, so it's more a point of what's idiomatic than what's possible.

~~~
jolux
C# 8 also has nullable reference types, i.e. comprehensive nullability
analysis, which is comparable though not identical to an option type. I really
wish for exhaustive pattern matching and ADTs in C#, though.

~~~
alkonaut
It always feels a bit half baked when the class library isn’t designed with it
though. It would be as if generics were added but not
System.Collections.Generic. So while I long thought it would be the perfect
addition to C#, I’m not so enthusiastic any more. It would be great (F# is!)
but not as good as it would be in a language and platform where it was there
all along.

In F# this is already an issue when you want to use Option/Result but as soon
as you do anything with the BCL you need to handle exceptions instead, and
convert to/from error cases of ADTs.

~~~
Merad
Nullable reference types also feel pretty half baked with EF at the moment. If
you have a non-nullable column that you want to represent with a non-nullable
property in your EF model, pretty much the only option (the last time I
looked) was to configure EF to use a nullable private field and access it
through a non-nullable public property. It's a lot of extra work.

------
joshsyn
I have been using F# since last year, haven't really looked back to C# since.

Unfortunately although we are a small community, it does feel like being last
on Microsoft priority list.

Microsoft please listen to feedback of your F# users namely on fslang-
suggestions and fslang-design repository.

My personal wish list for F# are type classes, HKTs, macros and GADTs.

~~~
daxfohl
I'm a bit curious about the constant need of hkts. I had a fairly manufactured
answer to the following question, which would have saved a couple keystrokes
with hkts, but I don't yet get why it is constantly so high on the request
list. It seems like something that is cool in theory but would rarely be used
in real world code.
[https://stackoverflow.com/q/21170493/171121](https://stackoverflow.com/q/21170493/171121)

------
throwawa66
Pattern matching is so much better in F#. C# gets more and bloated to the
point of paralysis. It's not yet there but I;m sure it will at some point.

~~~
czechdeveloper
Every single feature C# got in past years increased my productivity.

I understand that it may cause issues to new learners, but overall, what of
them do you consider bloat?

~~~
throwawa66
Wait till you get to work in some complex code bases and you'll understand why
jamming all kinds of idioms into one language can become a disaster. It's a
tool after all, if you know how to use it properly you don't paint yourself
into a corner. However, too much flexibility can lead to many problems in
larger teams. Good luck!

~~~
moron4hire
I don't know, what's easier to understand? Sorting a list with an IComparer
instance that you have to implement in a concrete data type somewhere, or just
tossing it a lambda expression? Just because it's new syntax doesn't mean it's
automatically more difficult to understand the language.

~~~
throwawa66
I got nothing against functional programming, I embrace it. However, im
stating again, shoving everything under one umbrella is bound to create a
complex monster. Functional programming is actually easier to understand in F#
rather than C#, the idioms do translate but clunkily. Do yourseves a favor and
spend some time outside C# and you’ll come back illuminated.

Not saying C# is bad, thats what you all seem to understand though.

Good luck to you all

~~~
graphememes
You find F# easier to work with. That's all. Doesn't mean others _must_ share
your opinion. Good luck to you.

~~~
throwawa66
Yes, its all subjective, I know. But stepping out of the garden is what I’d
like people to take out of this. Saying C# is the most beautiful language
(like some commenter states) is true only if you haven’t dabbled in many
languages. And once you do you feel stupid for having had this conviction in
the first place. Ive used C# throughout my career, I don’t diss the language
or the ecosystem, but other things are to be considered as well and
cargoculting is a thing

~~~
emodendroket
I've used a number of others and still appreciate C#, especially since it's
stealing all the features I liked

------
rkagerer
Here's an example of the new syntactic sugar:

    
    
        public static double ComputeArea(object shape) {
            switch (shape) {
                case Square s:
                    return s.Side * s.Side;
                case Circle c:
                    return c.Radius * c.Radius * Math.PI;
                case Rectangle r:
                    return r.Height * r.Length;
                default:
                    throw new ArgumentException(
                        message: "shape is not recognized",
                        paramName: nameof(shape));
            }
        }
    

The _when_ clause can be used to deal with special cases (e.g. to avoid
division by 0 when a dimension is 0).

~~~
aar0nsa3nz
With C# 8 you can also write it as:

    
    
      public static double ComputeArea(object shape) =>
        shape switch
        {
          Square s => s.Side * s.Side,
          Circle c => c.Radius * c.Radius * Math.PI,
          Rectangle r => r.Height * r.Length
          _ => throw new ArgumentException(
                 message: "shape is not recognized",
                 paramName: nameof(shape))
        };

~~~
Someone1234
Their long game is to slowly convert C# into F# without anyone realizing it.
They're roughly half way through already.

~~~
akra
From the features they are porting into the language I think this is the case;
albeit C# will always be the more verbose language and the features will feel
somewhat clunky at times IMO. Pattern matching, async yield return,
async/await, etc all were in F# in some form beforehand with features like
records and DU's probably being investigated as well. When I read a new C#
language version announcement it does feel like I'm reading a subset of the F#
feature list.

~~~
emodendroket
I used Scala for a bit and then came back to C# and felt like they were
porting over all the Scala features, but I think the F# explanation may make
more sense.

------
martijn_himself
This is neat, but also super confusing.

Is the ability to build class hierarchies not the ultimate reason to use C#,
an Object-Oriented language? Which one of the two is idiomatic?

Great, now we have code littered with methods that take _object_ s as
parameters, so we have no clue what to actually pass to the method?

C# is a fantastic language but I feel increasingly lost with the barrage of
new features added to it.

~~~
1propionyl
Class hierarchies are not a desirable feature of object-oriented languages,
they're an unfortunate side effect of their historical development. (For
example, early versions of Java did not actually have the interface keyword at
all.)

There are several very good reasons that the inherited wisdom about OOP
includes such phrases as "prefer composition and delegation over inheritance".

There are some cases where class hierarchies are actually good, but they're
far rarer than most would suspect. The Liskov Substitution Principle is less
of a guide as to how to use inheritance as much as it is a guide as to when
you should not be using inheritance at all.

And to address your point: the only time objects with class hierarchy and
subclases should be accepted as arguments to methods is precisely when the LSP
holds. Otherwise, you're gonna have a bad time.

~~~
martijn_himself
These are all valid points and it shows my lack of understanding (same with
the other comments), even though I use C# on a semi-regular basis I have a lot
to learn!

I don't envy any newcomers to the language though, there is so much to take
in.

~~~
1propionyl
My general advice to anyone working with C# is the same advice given by the
authors of Smalltalk to developers.

1) Always prefer composition and delegation to inheritance.

2) Always prefer interface inheritance to implementation inheritance _even if
in the short term it results in code clones_.

3) If you intend to have multiple subclasses that adhere to the Liskov
Substitution Principle, it is always better to have IFoo and X implements
IFoo, Y implements IFoo... than it is to have abstract class Foo where X, Y
extend Foo. You can still do that, behind the scenes, but your public
interface should whenever possible be nearly entirely interfaces and concrete
classes.

4) Inheriting the body/behavior of methods is seductive but ultimately only a
poor excuse for not delegating that will create maintenance headaches down the
line.

------
bilekas
I'm super embarrassed as a dotNet developer, at times 'engineer', that I don't
know this..

I can't list how many time's I've ran into this kind of issue when trying to
explain to a peer/intern.. (Only know I probably messed up a bit now) And HN
links like this just remind me that I would love to take a 'bus mans holiday'
just to catch up on the framework.

This is a huge plus to the benefits of sending employees and me (please send
me) to those release conferences. 'New dotNet Core coming ?' : I want to be
there, but I have to live in Europe and not able to take holidays, so the
stream is saved; I'll watch it later (I rarely do). :(

Whatever about patterns and higher level issues, knowing the framework is also
damn key important and often overlooked as a given. Really knowing the
framework, all the way down to the compile time really offers some incredible
results, I have been fortunate to work with some who really knew the framework
versions that we were in and it was always so much fun to put bets on how much
time that team would save from ours and other teams from even just a light
refactor. Most important is that developers should know the framework, not
because of high time savers, but so that nobody is re-writing the wheel
(intentionally did not say : 'not reinventing')

I wish I had the time to always dig through the release notes of the latest
framework abilities, not to mention 'Core'.. I might bring this up as a task
for the team, but does anyone genuinely have good suggestions on how to drill
into fellow team mates that its important to check up on framework
functionality..

I really feel kinda insulting to say: 'maybe google it to see if there is a
simular issue that could shine a light?'

God bless HN.

Edit: ReSharper is my best colleague.. I'll copy an important note from below:

>Note : I am not fighting against tools, just that sometimes, me included, the
tools make us not go and search why resharper is screaming: 'you're an idiot'!

~~~
GordonS
It's OK, C# is a living thing, don't feel bad!

I'm guessing you use Visual Studio and don't have ReSharper? If so, I have 2
recommendations to make:

1\. Get ReSharper! When it sees code that could benefit from language
features, it will suggest it

2\. Get JetBrains Rider - seriously, try it - it's an alternative IDE with all
the ReSharper stuff built-in. I personally find it a better experience than
Visual Studio, and it makes my laptop fans whine far less!

~~~
bilekas
1) I do have resharper, I made a comment here about how it makes me lazy
because it does it for me, and how I get nervous even jumping on a VS without
it

2)Rider though.. It's new to me.. I'll certainly give it a go.

But one of my main points was : 'Hey, we work with this language, we should
know it'

Get me ?

Note : I am not fighting against tools, just that sometimes, me included, the
tools make us not go and search why resharper is screaming: 'you're an idiot'!

------
vcool07
I'm surprised at the no. of recommendations for resharper even now. I thought
most of the new features of resharper was already included as part of VS2019.
Any specific feature that's missing ?

~~~
ygra
Resharper still has a bunch more refactoring and navigation tools. Whether
that's those that are missing and you're using them, is probably up to each
person themselves. The single feature I found missing all the time was smart
completion which suggested matching locals/properties based on the expected
type of arguments or missing expressions during typing. Everything else I tend
to use, navigating to files, types, members, basic refactoring (most-used are
extract local and extract method anyway) are all there and wouldn't need
Resharper.

------
SideburnsOfDoom
C# 8 also has "switch expressions" (1) meaning that all those "return"
keywords fall away

so this is valid (although useless) c# 8:

    
    
        public static bool Invert(bool value) =>
            value switch
            {
                true => false,
                false => true
            };
    
    

I worry though that the "switch" syntax is becoming a big complex monster, and
can be used to make utterly unreadable code, rather than simplifying as
promised. We'll probably see both in practice.

It might have been nicer if they could have used a new keyword e.g. "match" to
carry the new syntax, rather than overloading "switch", but that would not be
backwards compatible with C# 1-7, as "match" was not a reserved word. (2)

Hopefully switch the syntax that supports these various cases doesn't get too
tricky.

1) [https://docs.microsoft.com/en-us/dotnet/csharp/whats-
new/csh...](https://docs.microsoft.com/en-us/dotnet/csharp/whats-
new/csharp-8#switch-expressions)

2) [https://docs.microsoft.com/en-us/dotnet/csharp/language-
refe...](https://docs.microsoft.com/en-us/dotnet/csharp/language-
reference/keywords/)

------
totalperspectiv
At this point I would not be sad if I was forced to use C# for some reason.

~~~
bob1029
You should try it out sometime, regardless of coercion. There isn't much of a
barrier to entry anymore. Even installing VS2019 is a pleasant experience now.

I have yet to meet a developer who gave C# a legitimate try and then decided
it was entirely not for them. That said, I only personally know developers who
are working in the realm of B2B application development, so perhaps there are
other incompatible use cases that I am blind to from my current perspective.

~~~
DaiPlusPlus
Data science, vision, etc - this is where Python reigns supreme and using C#
is really going against the rest of the industry.

Using OpenCV from .NET is painful, but from Python it feels native.

~~~
totalperspectiv
Yeah, this is basically the boat I'm in. Python dominates. You either write it
in Python, or maybe get away with writing it in something else and then
wrapping it in Python.

I don't mind Python, but now that I've gotten a taste of ADT's and non-
nullable types, writing Python feels like a kludge.

~~~
DaiPlusPlus
Python (the language) feels more like a less-capable version of JavaScript now
- with all of the disadvantages of lacking AOT type-safety (I know static
type-checks are now available with 3.6 - but remember that most of the world
is still using Python2...).

------
jesseryoung
I've always seen switch statements as an anti-pattern in C#. These examples
however, do demonstrate neat time saving techniques.

Does anybody have examples of real-world use cases that take advantage of this
that couldn't (or shouldn't) be solved in a more OO way (Visitor, Strategy,
Template Method, etc)

~~~
JamesBarney
Why are switches an anti-pattern?

Switching a simple switch with a strategy pattern can make code far more
complex and hard to understand. Switches are simple to code, simple to read,
and easy to change.

~~~
tigershark
Because it’s a switch statement, not an expression and a lot of people tend to
use it for doing stuff more complex than a single line. Being it a statement
there is nothing that forces you to return from each case and you may forget
to use the break keyword mistakenly executing also the next case.

~~~
goto11
That is not the case in C# though, the break is required by the syntax.

------
brianpgordon
I don't think anyone has mentioned yet that this exact feature (with the "is"
keyword) is actually coming to Java as a preview feature in Java 14-

[https://openjdk.java.net/jeps/305](https://openjdk.java.net/jeps/305)

------
zwieback
Is type-sensitive code totally acceptable now? I do use it at times but
generally try to avoid it.

~~~
thurn
"Type-sensitive" code is encouraged when using the functional style, where you
treat objects as dumb "bags of data" that have no inherent functionality of
their own. It's still discouraged when following an object-oriented "smart
objects" pattern.

~~~
bernawil
How is that particularly functional? In Haskell the same example would be
approached at type-level using type classes, something extremely similar to
using Interfaces.

I guess in a dynamic functional language you'd probably avoid doing this type
of contact-oriented stuff, but you'd rather pass a callback at the last point
rather than check type of what you got passed.

~~~
emodendroket
I worked in Scala for a while and it was pretty common to use these kind of
pattern-match statements for a kind of dispatch mechanism. Not even
necessarily with types, it might be something like "do one thing when field a
is null and field b is not, another thing when it's the other way around,
another thing when they're both null, and still another when neither is." The
nice thing about it is the compiler can assert that your match is exhaustive.

~~~
bernawil
> do one thing when field a is null and field b is not

And that would have been a good example! contrary to the one in the docs.

Pattern matching for checking fields of things of the same type is a good use.
Pattern matching when checking your parameters type? bad.

> The nice thing about it is the compiler can assert that your match is
> exhaustive

If you pass a new Shape object for which you forgot to implement a new case in
the pattern matcher, you just get the default case, which is wrong, but the
compiler can't know that. Now have the function argument ask for something
that implements IArea interface and if you don't implement getArea() in your
new Shape class, the compiler will know.

~~~
emodendroket
Well I think it is pretty common to have a combination of these. You're right
that if you configure a default matcher the compiler can no longer tell if the
match is as exhaustive as you intended, but I think you can often just avoid
that altogether.

------
macca321
Apologies, but here's the obligatory link to my OneOf exhaustive type matching
library:
[https://github.com/mcintyre321/OneOf](https://github.com/mcintyre321/OneOf)

~~~
throwawayy8292
Hey I wanted to thank you! I stumbled across your repo a few years ago, when I
was looking at more powerful ways to use the C# type system. I ended up
pulling a heavily inspired version of your code into a utility library I made
(for a zero dependency package).

[https://github.com/Matthew-
Dove/ContainerExpressions#eithert](https://github.com/Matthew-
Dove/ContainerExpressions#eithert)

Once again - thanks for your contribution to my learning!

~~~
jodrellblank
Did you just dox your own throwaway?

~~~
throwawayy8292
Yep, just got excited when I saw a familiar name I guess. Nothing too
egregious on this account's history anyway.

------
qwerty456127
Cool. I bloody wish Python is going to introduce this (and immutable (single-
assign) variables) in near future.

------
tlwest
A new construct to save a line of code? Whatever happened to "every proposed
language feature starts at -100 points, and must must become positive to even
possibly be considered."?

Given that probably 90% of code is written by C or D class programmers, every
new feature adds cognitive load that makes it less likely that the median
programmer (who almost certainly works offshore and who likely doesn't have
enough English skills to process the tutorials) will write bug-free code.

Once upon a time MS understood that highly educated university graduates are
only a small percentage of the programmer market and kept that in mind.

Looking at the new language changes, that's been forgotten in order to please
the programming elite.

Spare a thought for the poor souls who curse every time Microsoft adds a new
blade to the Swiss Army knife of C# because they know they'll be the ones
mopping up the blood of the countless programmers who've cut themselves on the
new feature.

~~~
goto11
I feel for you! But people misusing language features is not really the fault
of the language per se, it is more a failure of process, culture, tests and
code reviews. I don't believe dumbing down a language leads to fewer bugs, it
will just lead to more verbose bugs.

------
The_rationalist
From PHP 8 union types to C# pattern matching, I find it beautiful how
languages tends to have more and more similar feature sets.It's like we're
reaching a consensus on which language constructs are beneficial.

------
agentultra
Java is getting tuples, PHP is getting union types, C# is getting pattern
matching... someone is going to announce algebraic data types and I'll die.

Nice work, C#!

~~~
tigershark
The proposed record implementation in C# is awful, so don’t hold your breath.

------
eyegor
Does anyone know of or can think of a use for (x is var y)? I'm assuming there
must be, but I just can't figure it out.

------
mindfulplay
Such a beautiful, elegant language. Simple to grasp and lets the compiler
handle all that legitimate complexity.

Wish more language designers would respect code authors like these designers
do.

~~~
mumblemumble
I suspect that it's not an issue of respect so much as an issue of governance.
C# remains a commercial language, wholly owned by a single corporate entity.
That, I think, allows its maintainers some luxuries that community languages
don't enjoy. Chief among them is a whole team of full-time language designers
and implementers who can sustain a sort of deep concentration 40-ish hours a
week for years on end. I'm pretty sure it's closing in on a decade that
there's been talk about how to implement pattern matching into C#, and I'm
absolutely sure that a lot of blood, sweat, and tears went into it. But that
kind of effort is more manageable, on a personal level, if you're getting paid
to do it and if most the thornier bits of the process are happening in a
private-ish space and among a small group of people you know well.

By contrast, with a community language where these decisions are made in
public, by committee, and perhaps by a team of volunteers, it seems like
things are always just a bit more strained. I'm sure some of the more famous
PEPs took a huge personal toll on GvR, and there's no doubt that they caused a
lot of high emotions. I see similarly troublesome patterns in Nim and Scala,
where it would seem that "trying to avoid too much conflict with people who
are forcefully communicating strongly held opinions over a medium like the
Internet where it's difficult to modulate emotions" can be a real factor in
the decision of what language features to include and how. And, in that kind
of environment, it's probably particularly difficult to keep the Internet,
with all its . . . Internetiness, at bay for long enough to really make sure
you've got all the details dialed in right. Much easier, I imagine, to go for
the punt and get the whole business over with.

~~~
Kipters
_Technically_ it's owned by .NET Foundation now, but admittedly it's composed
of MSFT people by a large part. Also, language design happens on GitHub, and
the community is encouraged to get involved.

~~~
oaiey
As long as Microsoft finances the .NET/C# team, neither runtime/libraries nor
the language will include anything which does not fit in their
strategies/vision. The .NET Foundation will not change anything here. And that
is good. The .NET Foundation ensures that the product is legally usable on
Linux/Macs/other non Windows platforms and additionally helps the ecosystem.

F# for example is set loose of these constraints.

~~~
Kipters
It has also brought stuff like ARM64 support (from Samsung and Qualcomm)
without having to wait for MS to do it though

