- Feature Articles
- CodeSOD
- Error'd
-
Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Tern Around Bright eyes
Admin
And I was expecting someone to have mis-spelt "ternary" somewhere in the post.
No, just lack of attention to detail.
Admin
Just out of interest, Remy, when you say you prefer optional types, do you mean actual optional types (eg Haskell's Maybe) or simply a nullable native type?
I'm asking because I'm trying to steer cow-orkers (oops, a pun) towards Maybe in C#. It's hard work to wean people off nulls.
Admin
Not Remy, but this is something I've also been dealing with lately. Personally, I've found nullable reference types in C# to be quite useful (by which I mean annoying enough to push people to resolve the nulls as early as possible and then use non-nullable refs from then on), assuming you're using a version of the language that supports that feature.
Admin
Maybe I'm not totally up on type theory, but aren't nullables just a special case of optional types? Is there some special magic that Haskell's
Maybe
or C++'sOptional
do that the nullable doesn't? I don't think there is. In C#, nullables are implemented basically the same way-Nullable<T>
as a wrapper class around some object which might be null. C# just chucks a bunch of syntatic sugar in there to make it read better.Admin
This article's (headline) is for the burds.
Admin
Nullable
is pretty muchOption
/Maybe
, yes. The catch is that C# references are always able to be null unless you turn on the nullability annotations, a fact that makes all of this less useful, and probably why Nullable was originally introduced to work only on value types.C# also didn't let you say
if(Foo.HasValue(out var v))
at the time, which helps the ergonomics a lot.Admin
Maybe (or Optional in some language libraries) can be considered as a wrapper for a value, rather than a directly nullable type. (It's actually an applicative functor, but who cares? The only thing you need to know is that you need to bind to something to get the value out.)
You can work directly with a nullable type in C#:
... but that isn't really much of an improvement on a naked null. In this case you will get a null exception. If you use a Maybe and it binds to an if/else (ie it doesn't allow you to deal with the wrapped value directly) then you force the consumer to consider the possibility that the wrapped value is null.
At least, that's the way it works in my implementation. Ideally you would use it in SelectMany for ILists (there is an implementation in GitHub), but that's only really useful if everything you deal with is an IList.
Admin
Then again, Nullable<T> appears to be pretty much the same thing. Except that it's only available in 8.0, and it needs to be switched on, and I haven't used it, but as far as I can see you get a compiler warning rather than being forced to bind to the underlying value.
Admin
Laughs in named parameters.
I'm rather surprised that no one has brought that up, as they are far superior in a lot of ways to ye olde positional arguments.
Admin
I should probably also point out that Rust and Haskell make Option/Maybe out of sum types (ie, "a Foo can be a Bar, Baz, or Quux", where any of those things can be just the name or include some data). So a bunch of ergonomics and implementation details comes from how the language handles those.
In particular, an Option-al reference (in a lang where references are never null) may well be implemented as a nullable reference (normally sum types are done as tagged unions). And pattern matching and destructuring assignment can be used to get at the inner value.
Admin
Code like that doesn't trigger an exception.
Prints "This is fine". Because the nullable operator is just a bit of syntatic sugar around
Nullable<double>
, sofred
does have a value and is not a null reference- the contents offred
are null. Similarly, if you didfred?.ToString()
that's actually going through theNullable
wrapper and just hiding the details from the developer.And I'm not sure what you mean about Version 8-
Nullable<T>
has been in .NET since .NET 2.0: https://learn.microsoft.com/en-us/dotnet/api/system.nullable-1?view=net-7.0#applies-to(There's a debate to be had about if that syntatic sugar actually makes the language better- more ergonomic, yes, but if you look at the Linq query syntax, you can see lots of opportunity for confusion because the code you write is nothing like what the compiler sees)
Admin
Be sure to keep your nulls fresh. Stale nulls are the primary cause of null pointer exceptions! ;-)
Admin
I think you mess up your example, because this translates to: `` .locals init ( [0] valuetype [System.Runtime]System.Nullable
1<float64> fred, [1] bool, [2] valuetype [System.Runtime]System.Nullable
1<float64>, [3] float64 )So perfectly fine and works as intended with no NullReferenceException potential.
Admin
Hehe, you shouldn't say your "bit of syntatic sugar" when someone of the .net language team is around. After all they had to complete respec the CTS to allow a value type be assigned null, changed the compiler accordingly and did a lot of magic to make everything work a smoothly as it is.
After all, nullable value types in C# are not reference types, they are value types boxing the value type with an additional boolean member.
Admin
I use Optional<T> types in Java (not familiar with C#, but I assume Nullable<T> is the same,) but mostly to make the code more fluent and as documentation. Since values can be null anywhere short of using piles and piles of @NotNull annotations everywhere, it really doesn't make a semantic difference.
A lot of people are talking about Haskell's Maybe type. In the ML family of languages like Haskell and OCaml, it really does make a difference. They don't have nulls; everything is a value. The only way to make something nullable is to be explicit about it and make it a "Maybe a" in Haskell or an " 'a option" in OCaml. The fact that it's done as a sum type (tagged union, variant, whatever you want to call it) is more of an implementation detail. It could just as well be built-in to the language semantics. Both Swift and Typescript do this by allowing types to be declared as "<type-name>?" to indicate optional types.
IIRC, Kotlin is a JVM language takes the same approach as the ML family of languages in that everything in non-null by default and nulls must be explicitly annotated.
Admin
Can't yet see WoO's comment, which will probably prove me wrong.
I've not done a good job of explaining my problem with returning nulls, which is programmers, basically. Let's try this with a non-native type:
This will of course throw an exception if fred is null. And it may be that the original implementation of GetSomethingThatMightBeNull never returns a null, in which case nobody cares. Nobody will really care when GetSomethingThatMIghtBeNull is reimplemented such that null is returned on the 4th July of every year that is divisible by four but is not a leap-year.
Then, suddenly, a perfectly innocent update causes GetSomethingThatMightBeNull to return a null every now and again during a normal session.
It's all about semantics, really. If you're going to force the consuming call to deal with nulls, then damn well force that semantic. Maybe forces that semantic. Nullable objects do not. (ANd trust me, I'm dealing with dozens of the bloody things in my current code base.)
Admin
Technically, this code is "terning" nulls into nulls, not values.
Admin
NULL, the worst thing ever created. Except all of the alternatives were worse.
Admin
Whether nullptr is better or worse than the alternatives seems to depend on whether said alternatives are retrofitted and how they work. Sum types work really well, with the right support, but if you staple any replacement for null on after the fact rather than have them from the start, there'll be lots of places that shouldn't be nullable but aren't declared null-free.
The refactoring to add that declaration is frequently easy, there's just a lot of it, and inevitably external libs will be unfixable.
Admin
Be very careful about doing comparisons involving potentially nullable values. The truth tables aren't always what you would expect. I ran into trouble with this where I got the opposite behavior of what I would expect when doing an If on a Boolean?.
VBA-heritage VB had specifically designed truth tables for null. I don't remember, offhand, whether the truth tables for Boolean? follow the historical truth tables.
In the specific case here, I would expect the result of "fred == 1" to be boolean? so the behavior of the "if" depends on how it handles a boolean? without a value.