Hacker News new | ask | show | jobs
by barake 991 days ago
You're likely in for a treat if you haven't written C# in a while. The language has evolved quite a bit, especially around all kinds of nice ergonomics. Interesting things like pattern matching, using statements, and performance oriented primitives.

I got back to writing C# full time earlier this year and it's a joy.

2 comments

I've been keeping up with the language and I am... Less than enthused.

Maybe I'm just yelling at clouds, but I see more bloat than useful features recently.

Non-nullable reference types as default was a bad idea and I will die on this hill

> Non-nullable reference types as default was a bad idea

Why?

Lots of reasons, but mainly that I don't consider null values to be a fault of the language. Even if it were, this doesn't solve that problem.

But now we're in a situation where we still have nulls, but compiler warnings force us to decorate them and treat them the same as before. It obscures the difference between value and reference types. Plus the syntax implies Nullable<T>, which is something everyone should have learned to avoid when all it did was box value types.

The more correct solution would have been to finish the contract system that allowed you to declare a function argument as non-nullable.

Ultimately I think it was the wrong solution to something that wasn't a problem to begin with. Now we have muddied the syntax and the null situation is the same as it always has been.

Agreed that Microsoft is adding features for the sake of setting C# apart rather than making it a better language (IMO).

I strongly disagree about the treatment of null values, if there's one thing I like about C# it's that (even if it's crude, it's better than Scala's way of doing it which is Maybe or Option or something, sorry, it's been a while.) Also C# doesn't 'force' you, you have to require it before it enforces no-nulls.

> It obscures the difference between value and reference types

How, and how is that a problem?

> Plus the syntax implies Nullable<T>, which is something everyone should have learned to avoid when all it did was box value types.

Err, now I'm getting really rusty. What are you saying here?

> The more correct solution would have been to finish the contract system that allowed you to declare a function argument as non-nullable.

That's effectively what the no-null enforcement does, only it applies inside a function as well (if you make it do so anyway).

I completely disagree that it "wasn't a problem to begin with" .Hoare called it his billion-dollar mistake, and that's an underestimate. And we haven't muddied the syntax because you enable no-nulls with a pragma, and the null situation is definitely not the same as it has always been. The compiler picks them up and reports them (like I said, rather crappily but it's a damn sight better than nothing).

The question mark to denote a nullable type is inherited from the .net framework days. You'd use that to mark a value type as nullable, which is syntactic sugar for Nullable<T>. Internally, that object stores a bool for IsNull and it packs your value into an Object. When dealing with value types, this results in a copy-by-value every time you access it, which is bad in most cases.

I don't like this solution because it reuses something that I've learned is a Bad Thing. Though I'm sure the current implementation just stores a reference to the object in question.

But fundamentally, I think nulls are a good thing. Null carries information. If C/++ can handle null pointers for the last 40 years, I think C# can handle it. But then again, maybe this is a problem domain that I've just never encountered. The only problems I have with nulls is around ergonomics, but the null coalescing and safe access operators solve that for the most part. Maybe it's a bigger problem at scale, I really wouldn't know. At the scale I operate at, non-nullable reference types causes more headache than it solves problems

I must admit to disliking C#'s functional libraries. I have wasted so much time trying to get the buggers into a pipeline. It becomes agonising in a way that doing the same thing in Scala was so very much a dream. I keep discovering the hard way, just don't do it (or just get a whole lot more experienced at it, although I don't know how without going through the pain barrier, and deeper each time, like Inception).

Could you give me a hint about these 'performance oriented primitives' please? (The only ones I can think of are structs versus classes) Edit: but isn't there a new thing where you can subtype a class without allocations, like Scala's record classes, or is that new in Java, can't remember.