[HN Gopher] C# 9 Pattern Matching
       ___________________________________________________________________
        
       C# 9 Pattern Matching
        
       Author : benaadams
       Score  : 53 points
       Date   : 2021-04-06 11:43 UTC (1 days ago)
        
 (HTM) web link (developers.redhat.com)
 (TXT) w3m dump (developers.redhat.com)
        
       | bob1029 wrote:
       | Pattern matching + switch expressions can make for really concise
       | and functional state machines which can be validated for coverage
       | at compile time.
        
       | spaetzleesser wrote:
       | I love these new additions because I like new stuff but I'll
       | admit it's hard to keep up and use things with good taste. C# is
       | becoming a BIG language similar to C++. But I guess that's the
       | only way to get a broad user base long term.
        
         | kemiller2002 wrote:
         | This is my fear. C# keeps adding things to appeal to a
         | different user base. What I've seen (anecdotally) is that most
         | C# devs don't know or don't use the new features. This pretty
         | much means they are useless to me, because even though I can
         | use them and understand the new features, other people can't.
         | The new code isn't maintainable to most people beyond me. Yes,
         | I can go and show them and train people, but really it comes
         | down to coding the imperative/oo way is what the majority of
         | people are used to.
        
           | emodendroket wrote:
           | The popularity of ReSharper really helps with this, I find.
           | People pick up the new features because ReSharper constantly
           | recommends them.
        
             | cfn wrote:
             | Resharper has also helped my code to "evolve" alongside the
             | language. In fact I learned LINQ with it. It is also very
             | easy to compare the different solutions for readability in
             | each case.
        
               | emodendroket wrote:
               | The Linq suggestions are the only one where I frequently
               | have to reject them for being unreadable, but overall yes
               | I agree.
        
         | mumblemumble wrote:
         | > C# is becoming a BIG language similar to C++.
         | 
         | Yes. And they're on roughly the same trajectory: start out as a
         | relatively small object-oriented and procedural language, and
         | then just keep piling on more and more and more features to
         | make the procedural programming more ergonomic. Including by
         | pulling in more and more stuff from functional programming.
         | 
         | On the one hand, it's hard for me to dislike adding pattern
         | matching _too_ much, because I do tend to prefer functional
         | programming. On the other hand, I 'm also familiar enough with
         | OOP (it's been most my career) to know that there's a huge
         | overlap between problems that pattern matching can solve, and
         | problems that dynamic dispatch can solve.
         | 
         | The thing is, in these examples of using pattern matching in a
         | language like C# or Python, I never see anyone even considering
         | the object-oriented solution to the problem. They just show how
         | gross the procedural version is. Which isn't quite enough in my
         | book. You don't just want to show that some existing language
         | features are a poor fit for the problem at hand, you want to
         | show that _all_ existing language features are a poor fit. And
         | somehow, despite these being object-oriented languages, the
         | object-oriented solution is never even being considered
         | anymore.
         | 
         | Is it because OOP is that bad? Or is it because we've been
         | badly taught? I know which answer is easier to argue for, but
         | I'm less and less convinced that that's because it's the best
         | answer.
        
           | jayd16 wrote:
           | In a lot of ways I think the OOP approach is just too
           | cumbersome.
           | 
           | If you imagine implementing a handler chain, the logic would
           | be quite verbose and distributed. You might want to use an
           | inline type definition. Then you might want to use an
           | anonymous types, then lambdas.
           | 
           | Then you realize that pattern matching is just a sugared
           | version of the OO handler chain.
        
             | mumblemumble wrote:
             | I was actually thinking something simpler; just having all
             | your types implement an interface, and then following the
             | general "tell, don't ask" dictum.
             | 
             | Handlers are useful for some more complex use cases, as is
             | the visitor pattern, but they're frankly overused. It's
             | often enough to create an interface and let the classes
             | handle their own class-specific logic.
             | 
             | And polymorphism is not just a sugared version of pattern
             | matching. Each gives you a different kind of flexibility.
             | Polymorphism makes it easy to add new types to an existing
             | set of operations, and pattern matching makes it easier to
             | add new operations to an existing set of types.
             | 
             | Which one you need depends on your use case. The common
             | knowledge can get a bit tricky here, though. For example,
             | functional programming is often touted as being ideal for
             | programming language experimentation, because you have
             | pattern matching, but I have found that OOP is more to my
             | taste in this area. The reason is because, nowadays, the
             | set of basic operations a compiler or interpreter needs to
             | do is fairly well-established and static. But the list of
             | things you need to operate on - that is, the set of
             | features in the language you're implementing - will change
             | as you add or remove features from the language.
        
         | dnautics wrote:
         | Go is a relatively simple language that doesn't look like it's
         | getting much bigger and I'm pretty sure it has a fairly broad
         | user base.
        
           | emodendroket wrote:
           | Dwarfed by that of C#, but it's also going for something
           | rather different that was never attainable by C# in the first
           | place.
           | 
           | Also, I'm kind of on the fence about Go. I was charmed by how
           | easy it is to read and their error handling strategy
           | admittedly has benefits. But it is awfully tedious to write.
        
             | politician wrote:
             | I wrote C# for a long time, incl. low-level systems work at
             | the C#/C++ boundary, heavy reflection and simulation
             | systems, and numerical processing.
             | 
             | I prefer Go immeasurably. All of the same scope is
             | achievable, but I'm not constantly assaulted by new syntax,
             | unwieldy OO hierarchy towers of Babel, or broken data
             | frameworks.
             | 
             | foo, err := DoIt() if err != nil { return err }
             | 
             | is a small price to pay for sane control flow in the
             | presence of exceptions. I can debug code in Vim without
             | needing Reflector and Visual Studio to make sense of what
             | I'm looking at.
        
               | emodendroket wrote:
               | The thing is, yeah, any one of those verbose things
               | wouldn't be a big deal. But there are actually quite a
               | few and it adds up over time.
        
             | dnautics wrote:
             | No argument.. I strongly dislike go, myself.
        
           | dustinmoris wrote:
           | Ironically I'm mostly abandoning C# and using Go for the
           | majority of my new development now. I really like the
           | simplicity and stability of Go. The compiler speed, the
           | tooling, gofmt, and lots of other goodies just make it a very
           | refreshing change. I'm sure in 5 years time Go will also feel
           | less refreshing, but I have a feeling that my Go code today
           | will not look vastly different to my Go code in 5 years time
           | and that is very attractive. Also Go really allows one to
           | hire anyone. You can literally just hire a smart person and
           | let them learn Go on their first day on the job which will
           | make them good enough to start picking up the first tasks and
           | be productive. There are not many languages which can do
           | that.
        
             | emodendroket wrote:
             | That's the pitch but I'm also kind of tired of reading Java
             | with Go syntax.
        
             | merb wrote:
             | > You can literally just hire a smart person and let them
             | learn Go on their first day on the job which will make them
             | good enough to start picking up the first tasks and be
             | productive.
             | 
             | you can be productive on the first tasks in any language.
             | that is a stupid pitch. bad code can be written in any
             | language, especially in golang. I've seen as many bad code
             | in golang than in other languages. and fixing bad code in
             | golang is way worse than in some other languages.
        
           | Igelau wrote:
           | Go has the opposite problem. It's not getting big enough.
           | Last I checked, they couldn't be bothered to add integer
           | exponentiation.
        
             | recursive wrote:
             | C# also doesn't have integer exponentiation.
        
               | Garvey wrote:
               | It has since .Net 4.0, but does require using BigInteger
               | 
               | https://docs.microsoft.com/en-
               | us/dotnet/api/system.numerics....
        
               | recursive wrote:
               | That's a stretch. There's no language support for it in
               | terms of an operator, and it's in a package that's not
               | referenced by default.
        
         | ed_elliott_asc wrote:
         | Problem is if they don't keep making changes people start
         | asking why it has been abandoned
        
       | infogulch wrote:
       | I'm looking forward to Discriminated Unions being finalized. One
       | day... https://github.com/dotnet/csharplang/issues/113
        
         | gsuuon wrote:
         | F# is slowly making it's way into C#... but you could also just
         | skip the wait and start using F# :p
        
           | infogulch wrote:
           | You're like the fourth person to tell me that. Maybe I should
           | listen...
        
             | hurril wrote:
             | I've been writing F# professionally for 1.5 years now and
             | let me tell you: it is a BLISS! Came from Scala so no .NET
             | experience at all before.
        
           | thrower123 wrote:
           | The thing about waiting for C# to pick over F# is that
           | JetBrains keeps up with everything new the C# team does.
           | 
           | I really would like to make myself use F# more, but at the
           | end of the day, the tooling is not as good as for C#, and it
           | feels like a step backwards.
        
       | rohittidke wrote:
       | i have been using C# since 2010.I find it a good language but I
       | believe the future is not for strict statically typed languages
       | and but for smart linters which probably could take over
       | compilers.
       | 
       | The effort you put into strict types doesn't deliver the returns.
       | Languages like Typescript incmy opinion are the best as they
       | provide optional typing and support things mixins for example
       | which is difficult to implement in C#
        
       | [deleted]
        
       | Igelau wrote:
       | C# has some wonderful quality of life improvements over, say,
       | Java. I had to learn it in a rush for a job and really loved the
       | language.
       | 
       | Unfortunately, it was the worst job ever. Abusive, corrupt
       | environment. I found a subtle accounting glitch that no one else
       | seemed to quite understand. Assuming good faith, I showed
       | mathematical proof for it, and I was canned shortly thereafter.
       | On its own, the glitch wasn't too serious, but I suspect people
       | were nervous that I was digging too close to something else.
       | 
       | Never bothered to set up the env at home again after that on
       | account of the foul taste in my mouth, but that was hardly C#'s
       | fault. Just found other things to do.
        
         | haolez wrote:
         | Heard a similar story from a close friend. Also a C# shop. A
         | few months after, the glitch was indeed due to corruption and
         | some middle managers were stealing money. They went to jail
         | soon afterwards.
         | 
         | Maybe this just means that C# is widely used in places where
         | fraud can result in big gains.
         | 
         | EDIT: what I meant is that C# is probably used a lot in
         | accounting departments, for example. I'm not trying to imply
         | that C# invites fraud :)
        
           | kahrl wrote:
           | _Maybe this just means that C# is widely used in places where
           | fraud can result in big gains._
           | 
           | No.
        
             | [deleted]
        
             | damagednoob wrote:
             | Are you sure? I mean, there's at least _2_ data points.
        
               | Someone wrote:
               | Not even that. Could be two comments about the same data
               | point.
        
               | merb wrote:
               | well with this growth rate it could mean that in a few
               | months with have dozens of c# companies with abusive
               | managers.
        
           | dgritsko wrote:
           | It's more just that "C# is widely used".
        
       | The_rationalist wrote:
       | if (person is not null)
       | 
       | I really like it, it is more instantaneously readable than the
       | usual != as it is more literate.
        
         | alkonaut wrote:
         | It's also in some edge cases more correct, because you can't
         | trust != to actually check for null. That edge case is when
         | your (favorite) coworker did
         | 
         | public static bool operator != (YourType x, YourType y) =>
         | DateTime.Now.DayOfWeek == DayOfWeek.Thursday;
         | 
         | Note to self when designing a language: no operator overloads
         | on reference types.
        
           | doodpants wrote:
           | Ok, but if you have a coworker who's going to maliciously
           | overload operators to behave differently than expected, then
           | all bets are off and you have much bigger problems than how
           | to check for null.
        
             | jayd16 wrote:
             | Its not malicious or unheard of. Unity, a very popular game
             | engine, overloads the == operator as well as the implicit
             | boolean cast for their built in types. They do this because
             | their types adhere to a specific lifecycle. When an object
             | is dead, == null is true.
             | 
             | I'm not a fan and its not super common but it happens.
        
             | alkonaut wrote:
             | I was half joking, obviously this is hopefully not done out
             | of malice and hopefully whoever overloads the operator
             | still handles the case != null _logically_ equal to the
             | expected way. There could be smaller differences than true
             | correctness like performance too, not least since the !=
             | will be a virtual call that must be resolved, and also the
             | overloaded implementation may or may not be as efficient as
             | "is not null" is.
             | 
             | This is a similar same issue as the "what's wrong with
             | using String instead of string" when it only breaks if
             | someone adds their own type and calls it String, or aliases
             | a type to String (with a capital S). This actually happens
             | in actual code bases for various reasons not necessarily
             | malicious.
        
         | mrkeen wrote:
         | Person should have type Person, and null should have type Null.
         | Then the compiler could make sure you didn't ever mix the two
         | up! But I guess that ship sailed a while ago, and enough has
         | been written on the matter.
         | 
         | I think I dislike `is not` though, mostly because `!=` still
         | exists so now there's two of them. I already use the wrong null
         | check in SQL[1], I don't want to use it in C# too.
         | 
         | [1] https://stackoverflow.com/questions/5658457/not-equal-
         | operat...
         | 
         | > To compare if your value is not null, you use IS NOT NULL,
         | while to compare with not null value, you use <> 'YOUR_VALUE'.
         | I can't say if my value equals or not equals to NULL, but I can
         | say if my value is NULL or NOT NULL. I can compare if my value
         | is something other than NULL.
        
           | Guillaume86 wrote:
           | > Person should have type Person, and null should have type
           | Null. Then the compiler could make sure you didn't ever mix
           | the two up! But I guess that ship sailed a while ago, and
           | enough has been written on the matter.
           | 
           | You can somewhat get that in C# nowadays:
           | https://docs.microsoft.com/en-us/dotnet/csharp/nullable-
           | refe...
        
           | nikeee wrote:
           | > think I dislike `is not` though, mostly because `!=` still
           | exists so now there's two of them.
           | 
           | Note that "!= null" may behave differently than "is not
           | null". != is an operator that can be overloaded, "is not" is
           | not. Same counts for "is" and == when checking for null.
        
         | moomin wrote:
         | It's nice, but C# already had `person is {}` which whilst it
         | requires a bit more familiarity with C# extends to more uses
         | like `person is { name: "Rationalist" }`.
        
           | MarkSweep wrote:
           | You can also do "person is object", which seems to make sense
           | to me.
        
         | jayd16 wrote:
         | As mentioned in the link. Those are not equivalent because the
         | != operator can be overloaded. I believe this is a less verbose
         | version of                   if(Object.ReferenceEquals(person,
         | null))
        
       | belinder wrote:
       | > An interesting case is the is not null pattern. This will check
       | whether the reference is not null. Using != null may check
       | something different when the type overloads the != operator.
       | 
       | If it doesn't use the != operator then what does it use? How does
       | it work with Nullable<T> which relies on that
        
         | rzzzt wrote:
         | Probably always the default implementation of != (reference
         | non-equality for objects), irrespective of whether an
         | overloaded version exists.
         | 
         | This SO answer has a snippet of the specification that may be
         | relevant: https://stackoverflow.com/a/7346086
        
         | MarkSweep wrote:
         | I think this sharplab link might help[1]. You can see that
         | pattern matching generates the same code as using "== null".
         | You can see that Nullable<T> is handled when the parameter type
         | is a nullable int. When a Nullable<T> that has no value
         | (HasValue == false) is cast to Object, it gets converted to a
         | null reference. So the comparison will work as expected.
         | 
         | When operating overloading is involved[2], different code is
         | generated.
         | 
         | [1]:
         | https://sharplab.io/#v2:C4LglgNgPgAgTARgLACgYGYAEMEDZtyYDCmA...
         | 
         | [2]:
         | https://sharplab.io/#v2:C4LglgNgPgAgTARgLACgYGYAE9MGFMDeqmJ2...
        
       ___________________________________________________________________
       (page generated 2021-04-07 23:02 UTC)