Hacker News new | past | comments | ask | show | jobs | submit login
C# 9 Pattern Matching (redhat.com)
64 points by benaadams 4 days ago | hide | past | favorite | 61 comments





I'm looking forward to Discriminated Unions being finalized. One day... https://github.com/dotnet/csharplang/issues/113

F# is slowly making it's way into C#... but you could also just skip the wait and start using F# :p

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.


I feel that. It always seems to come down to tooling; the moment you have to fight with tooling for a language, it immediately adds friction. Sure, individual developers can overcome these problems, but it still decreases the adoption rate of said language.

It makes me wonder what differed between the .NET and JVM runtimes, with .NET moving towards fewer languages, whereas the JVM supports more.


Microsoft seems to have some issues keeping their teams running, the Common Language Runtime has turned into C# Language Runtime, as VB doesn't get feature parity with C#, F# is only considered for writing libraries, and C++/CLI is kept alive thanks to WPD and some key partners.

Meanwhile on the native side C++/CX gets killed and replaced with C++/WinRT, lacking VS tooling and no roadmap to when it will ever get it. It is already 5 years old.

.NET Native is stuck in C# 7 and VB 15, without any clear road if it will ever be updated.

Project Reunion started one year ago as the big reunification of Win32 and UWP application models, and what we got was a tiny 0.5 release, where lots of stuff is missing, not clear roadmap on the UWP transition, Xbox and HoloLens support, VS XAML designers are planned only for 2022, if we get lucky and the project doesn't get ramped down.

Just check some of the repos on GitHub and the endless amount of open issues.

Sometimes I wonder what is everyone actually doing.


You're like the fourth person to tell me that. Maybe I should listen...

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.

How does one find a job where the company uses F# or where the team is open to it?

Come to Sweden, we have cake and we eat it too :)

The 'Who is hiring' monthly posts on HN are a good source. There are a couple of companies hiring F# talent (shameless plug: Lokad does).

With the productivity drop of lack of tooling for some key .NET scenarios that only consider C# and VB.

Pattern matching + switch expressions can make for really concise and functional state machines which can be validated for coverage at compile time.

I would love to see this in action. Do you know of any repos that are doing this?

If you have the time, there's this great talk by Bill Wagner that goes over some of these newer features. You can also skip right to the pattern-matching section; he shows a good example of how powerful switch expressions can be.

https://m.youtube.com/watch?v=aUbXGs7YTGo

Alternatively, this page on the C# 8 release has good examples too. They show how you can leverage tuples to make them even more powerful.

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csh...


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.

> 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.


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.


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.


In my personal opinion when I'm reading code and trying to follow execution flow, OOP's "Everything happens elsewhere" approach is really annoying. In a Java codebase for example I would need to find all implementing classes, then search for that one method being called in each separate file. This means opening multiple files and searching for a few lines of code in each file, just to see what happens.

Written in a pattern-matching style there is a nicer correspondence between code-locality and execution-locality - which matches my mental model much more nicely, rather than OOP's colocation of different behaviors on the same entity


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.

The popularity of ReSharper really helps with this, I find. People pick up the new features because ReSharper constantly recommends them.

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.

The Linq suggestions are the only one where I frequently have to reject them for being unreadable, but overall yes I agree.

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.

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.


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.


> I can debug code in Vim without needing Reflector and Visual Studio to make sense of what I'm looking at.

Every time I hear someone say something like this, I have a mental image of people manhandling 200kg crates while the forklift sits idle because they can't be bothered learning how to drive it.

Reminds me of that multi-million dollar German-made road resurfacing machine that sat unused in some US city because the road crew thought it was too complicated to learn. Sure... they'd have to read the manual and learn to operate it, but that would only save millions of dollars in labour!


I agree with your sentiment, but if we want to be charitable to the OP, debugger or not, code that's easier to reason about is easier to debug. Whether that's true of the particular languages in question is another matter of course.

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.

No argument.. I strongly dislike go, myself.

Go has the opposite problem. It's not getting big enough. Last I checked, they couldn't be bothered to add integer exponentiation.

C# also doesn't have integer exponentiation.

It has since .Net 4.0, but does require using BigInteger

https://docs.microsoft.com/en-us/dotnet/api/system.numerics....


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.

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.

> 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.


The thing about it, I think, it that it is very _simple_, in terms of the primitives it gives you, but it wants you to do things differently than you're probably used to.

That's the pitch but I'm also kind of tired of reading Java with Go syntax.

Problem is if they don’t keep making changes people start asking why it has been abandoned

> 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


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...


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


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#


if (person is not null)

I really like it, it is more instantaneously readable than the usual != as it is more literate.


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))

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.


> 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.


> 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...


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" }`.

You can also do "person is object", which seems to make sense to me.

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.


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.

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.


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.


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.


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 :)


Maybe this just means that C# is widely used in places where fraud can result in big gains.

No.


Are you sure? I mean, there's at least _2_ data points.

Not even that. Could be two comments about the same data point.

well with this growth rate it could mean that in a few months with have dozens of c# companies with abusive managers.

It's more just that "C# is widely used".



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: