top of page
Search
gypsyreeks47085r

Reminder: Handling Nullable Types in LINQ - Learn the Basics and Advanced Techniques



In this post, we have seen that APIs that do not yet use nullable reference types may lead to incorrect code analysis, thus compromising null safety. ReSharper and Rider recognize such APIs and uses JetBrains.Annotations, if available, to ensure null safety.


Though this question has been already answered but I would like to give my suggestion to use Nullable types if you are using .Net 2.0 because for the same problem Nullable types were introduced in .Net 2.0 and provides the true safety when working with the database where a columns type is nullable but C# types do not support to have null values in them because they are value types.




Reminder: Handling Nullable Types in LINQ



Recently nullable reference types have become trendy. Meanwhile, the good old nullable value types are still here and actively used. How well do you remember the nuances of working with them? Let's jog your memory or test your knowledge by reading this article. Examples of C# and IL code, references to the CLI specification, and CoreCLR code are provided. Let's start with an interesting case.


Note. If you are interested in nullable reference types, you can read several articles by my colleagues: "Nullable Reference types in C# 8.0 and static analysis", "Nullable Reference will not protect you, and here is the proof".


Here we will look at the basics of nullable value types in general: what they are, what they are compiled into in IL, etc. The answer to the question from the case at the very beginning of the article is discussed in the next section.


This method copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument.2Reference parametersThis method copies the reference to the memory location of an argument into the formal parameter. This means that changes made to the parameter affect the argument.3Output parametersThis method helps in returning more than one value.C# - NullablesC# provides a special data types, the nullable types, to which you can assign normal range of values as well as null values.


The null coalescing operator is used with the nullable value types and reference types. It is used for converting an operand to the type of another nullable (or not) value type operand, where an implicit conversion is possible.


Edit: I see I was misunderstood. I understand and agree with the advantages of avoiding null pointers. I'm not talking about arbitrary pointers that accept null. I'm only asking why not use compile-time metadata, like C# 8's nullable reference types and TypeScript with strict null checks, where default pointers can't be null and there's a special syntax (mostly ?) to indicate a pointer that can accept null.


In the case of C# the language, the type system is sufficiently complex to support an Optional type allowing value types to gain a nullable state, but there isn't a trivial way to remove nullability from the object references.


Some systems prefer to have very simple primitive types, and rely on a powerful type composition system to create the desired behaviours. In these languages a C# nullable Reference might look like def cs_reference(T) => NULL T. The Optional pattern makes more sense though in these languages: def Option(T) => T[0..1]. Its an array/list/sequence of 0 or 1 element.


Dictionaries are just an example, the problem arise anywhere you have a data-structure with multiple levels of optional elements. Nullable types prevent polymorphism: code can't manipulate data of an unknown type generically, it has to treat nullable and non-nullable types differently.


Those types of static checks are a relatively recent invention. They were invented in response to options, as a way to pull in the benefits of options without the memory overhead and with a more familiar syntax. So a big part of the reason why more languages don't use statically-checked nullables is because options were invented first.


This is incorrect. Nullables have exactly the same overhead as option types in Rust, and overall the overhead can go either way depending on the language design. You can have option types with no overhead over nullables, and you can have nullables with overhead over option types.


In Rust, Option is represented by a nullable pointer. If anything, Option is more efficient than some languages with null because Option lets you represent optionals as stack based value types, whereas in languages with null these optionals need to be heap-allocated so that null can be used.


Whether Nullables or Options are better is a hotly debated issue among programming language enthusiasts. There is nothing objectively superior about Option types, just certain use cases it happens to excel at. Likewise for nullables; it's situational.


Semantically, Options and nullable types are pretty similar. Option and T? work pretty much the same. There are some differences like explicit Some and methods that operate on options. But you indicate that's not what you are interested in. Rather, you seem more interested in the implementation detail of using null pointers rather then some sort of enum.


Another way of looking at this, most types in Rust are value types not reference types. Thus nullable versions of those types couldn't be implemented as null pointers. They'd have to implemented as a value with a flag, which is how enums are implemented.


Furthermore, this is a relatively obvious optimization. I suspect that all languages with optional types that care about performance will ensure it gets implemented as a null pointer when that is suitable. So, there is no performance reason to shy away from Optional types in favor of nullables.


In C# with nullable reference types the null-coalescing operator ?? already implements the desired functionality. (If you're using another language or an older version of C#, you can instead use Maybe.)


I added the [Required] attribute to the ReservationDto class' Email property. Since this code base also uses nullable reference types, it was necessary to also annotate the property with the [NotNull] attribute:


This code snippet demonstrates how to parse, not validate, an incoming Data Transfer Object (DTO). This code base uses C#'s nullable reference types feature to distinguish between null and non-null objects. Other languages (and earlier versions of C#) can instead use the Maybe monad. Nothing in this article or the book hinges on the nullable reference types feature.


Instead of basing the design on nullable reference types or the Maybe monad, you can instead base parsing on applicative validation. In order to explain that, I'd first need to explain functors, applicative functors, and applicative validation. It might also prove helpful to the reader to explain Church encodings, bifunctors, and semigroups. That's quite a rabbit hole to fall into, and I felt that it would be such a big digression from the themes of the book that I decided not to go there.


  • See also Composition over aggregation, not just inheritance

  • Libraries should not provide interfaces for Dependency Injection - and stop asking

  • Parsing with Parsec: or, optional, retry and back-tracking

  • Stringly-typed: it's not that simple!

  • One recursion for all! Catamorphism step by step

  • Postel's law is simple - to fulfil the potential of your code

  • Unions are Untagged, and should be Discriminated in TypeScript: undecidable, collapse, and anti-patterns

  • PATCH-friendly types: null confusion, undefined envy and maybe maybe

  • void vs unit: Respect the Honesty of void

  • Reflections, Broken Promises and Fake generics: the anti-pattern

  • Generics: are you keeping it generic?

  • Abilities by birth? Separation of types, data and behaviour

  • Type Witness: not yet TypeScript, sure thing Haskell

  • Not assignable? A must-cast situation! TypeScript, wise 'as any'

  • Functions and classes don't mix - not always

  • Readability misses the point - look instead at vocabulary

  • Is TYPEScript Turing complete? Not sure. Game of life? Why not!

  • Golang error handling: yes to values, no to exceptions, a win for the future

  • TypeScript Fireworks: Union, Intersection and Variance

  • TypeScript: Convert Union to Tuple/Array, Yes but How?

  • Types or Operations: keep it closed, or keep it open

  • Ad-hoc polymorphism: Same input, different output, still pure

  • Architecture? You mean spreadsheets?

  • A taste of Rust

  • Your tests may belong elsewhere

  • Dependency hell? Not if we use functions! For library authors

  • Linq is Lazier, not by too much, just within Range

  • The TypeScript Handbook, Optional Parameters and Postel's Law

  • On accidental code deletion as reason for unit testing

  • A truly strongly-typed printf in TypeScript

  • Literal type preservation with TypeScript

  • Dependent Types in TypeScript, Seriously

  • Also on Comonad and Conway's game of life

  • Self-referenced JSON?

  • Plain and simple state management

  • The 'Constants' file is an anti-pattern, so is the 'Interface' folder. Placement by functionality, not technical concerns

  • Setting CAP loose in real life

  • Good code does not matter... not that much

  • Tuck-away and take-one, whatever it takes to look declarative

  • The Diamond, squashed and recovered

  • Dependent types in TypeScript?

  • Reducer to reduce, with lens in OO flavour

  • Nesting and positions in covariance and contravariance,

  • T.D.D. is most practical data-driven with pure functions

  • Covariance and contravariance

  • the magic Const, Identity and tuple

  • Out-of-context string template is an anti-pattern

  • Types, names, and type superstition

  • Types and tests: JavaScript 10, Idris 0

  • 2-layer architecture

  • Don't null check, just continue!

  • Make unit testing a breeze by segregating complexity

  • Inject functions, not interfaces

  • foldl in terms of foldr

  • Serialize like javascript - the idea

  • Serialize like javascript - MergeJSON in Idris!

  • My take on (unit) testing

  • callCC in Haskell, and my ultimate Monad

  • Coding an alternative Vect.index, Type-Driven Development in Idris

  • Fin

  • Lens (really record viewer / updater) in TypeScript

  • LINQ, infinity, laziness and oh my!

  • A few things about unit testing

2ff7e9595c


1 view0 comments

Recent Posts

See All

Comments


bottom of page