Why is the following forbidden?
Nullable<Nullable<int>>
whereas
struct MyNullable <T>
{
}
MyNullable<Nullable<int>>
is NOT
This is because the struct constraint actually means 'not nullable' since Nullable, despite being a struct, is nullable (can accept the value null) the Nullable<int> is not a valid type parameter to the outer Nullable.
This is made explicit in the constraints documentation
where T: struct
The type argument must be a value type. Any value type except Nullable can be specified.
See Using Nullable Types (C# Programming Guide) for more information.
If you want the rationale for that you would need the actual language designer's comments on it which I can't find. However I would postulate that:
the compiler and platform changes required to achieve Nullable in it's current form are quite extensive (and were a relatively last minute addition to the 2.0 release).
They have several potentially confusing edge cases.
Allowing the equivalent of int?? would only confuse that since the language provides no way of distinguishing Nullable<Nullable<null>> and Nullable<null> nor any obvious solution to the following.
Nullable<Nullable<int>> x = null;
Nullable<int> y = null;
Console.WriteLine(x == null); // true
Console.WriteLine(y == null); // true
Console.WriteLine(x == y); // false or a compile time error!
Making that return true would be very complex and significant overhead on many operations involving the Nullable type.
Some types in the CLR are 'special', examples are strings and primitives in that the compiler and runtime know a lot about the implementation used by each other. Nullable is special in this way as well. Since it is already special cased in other areas special casing the where T : struct aspect is not such a big deal. The benefit of this is in dealing with structs in generic classes because none of them, apart from Nullable, can be compared against null. This means the jit can safely consider t == null to be false always.
Where languages are designed to allow two very different concepts to interact you tend to get weird, confusing or down right dangerous edge cases. As an example consider Nullable and the equality operators
int? x = null;
int? y = null;
Console.WriteLine(x == y); // true
Console.WriteLine(x >= y); // false!
By preventing Nullables when using struct generic constraint many nasty (and unclear) edge cases can be avoided.
As to the exact part of the specification that mandates this from section 25.7 (emphasis mine):
The value type constraint specifies that a type argument used for the type parameter
must be a value type (ยง25.7.1). Any non-nullable struct type, enum type, or type
parameter having the value type constraint satisfies this constraint. A type parameter
having the value type constraint shall not also have the constructor-constraint.
The System.Nullable type specifies the non-nullable value type constraint for T.
Thus, recursively constructed types of the forms T?? and Nullable<Nullable<T>> are prohibited.
I believe you can only use non-nullable value types in Nullables. Since Nullable itself is nullable, nesting this way is prohibited.
From http://msdn.microsoft.com/en-us/library/kwxxazwb.aspx
public Nullable(
T value
)
Type: T A value type.
Nullable is special because there's explicit support for boxing and unboxing of Nullable types built into the CLR:
If you use the MSIL box instruction against a Nullable<T>, you will actually get a null as the result. There's no other value type which will produce a null when boxed.
There's similar and symmetrical support for unboxing.
The generic type parameter for Nullable must itself be a non-nullable type (i.e. value type). This is the C# compiler warning I get, and it would seem to make sense. Tell me, why would you want to do such a thing anyway? I personally can see no use, and little meaning to such a declaration even.
Nullable allows you to take a value type and make it like a reference type, in the sense that the value either exists or not (is null). Since a reference type is already nullable it is not allowed.
Quoted from MSDN:
The Nullable(T) structure supports
using only a value type as a nullable
type because reference types are
nullable by design.
Related
If F were "on" a, I could do this...
var obj = a?.F();
If F is not on a, I have to do this...
var obj = a == null ? null : MyFunc.F((A) a);
Or do I? Is there a more succinct way of skipping the method call if a parameter value is null?
The short answer is no, there's no succinct way to do that.
The slightly longer answer is still no, but there's an interesting language design point here. C# was designed by people with extremely good taste, if I say so myself, but it was designed over a very long period of time. Nowhere is this more obvious than with respect to its treatment of nullability.
In C# 1.0 we had a straightforward language in the tradition of C, C++, Java, JavaScript, and so on, where there are references and values, and references can be null. This has benefits; if it did not, Sir Tony would not have invented the null reference in the first place. But it has downsides: we have the possibility of null references, dereferencing null leads to program crashes, and there is an inconsistency between reference and value types: reference types have a natural "no value" value, and value types do not.
In C# 2.0 we added nullable value types, but nullable value types do not behave like nullable reference types. Of course nullable values types are not references, so you cannot "dereference" them, but if we squint a little, the .Value property looks a lot like "dereferencing", and it leads to a similar crash if the value is null. In that sense, they behave the same, but in other senses, they do not. Adding together two nullable integers does not crash if one of them is null; instead, the result is also null.
So at this point we have a contradiction built into the language:
Using a null value of a nullable value type usually automatically propagates the null, but using a null reference can crash.
And of course C# has then gone on to add a variety of features that make null references behave more like null values, like ?. and the related operations. There are also proposals for C# 8 that are very exciting, and will support "non nullable reference type" scenarios.
But the bolded text above is the fundamental problem you've pinpointed: the semantics of operators on nullable reference types are almost always "lift the non-nullable version of the operator to nullable types; if all the operands are non-null then the result is the same as the unlifted version; otherwise, the result is null". However, those semantics are not automatically extended to the . member access operator or the () call operator, regardless of whether the operands are nullable value types or nullable reference types. . can be lifted explicitly by ?. but the () operator does not get lifted to nullable semantics, ever.
Imagine a language like C# 1.0, but with Nullable<T> built in from the start, such that it applied to both reference and value types. In that world, you can see natural ways to implement generalized lifting, where if you have a method
class C { string M(double, int[]) }
and you call it with a Nullable<C> receiver, or Nullable<double> and Nullable<int[]> arguments, you automatically get the code that we build for you for nullable integer arithmetic: check whether the receiver or any arguments are null, and if they are, result in a null Nullable<string>. Otherwise, call the function normally and use the non-nullable result.
The C# compiler already implements these semantics for all user-defined operators declared on struct types; it would not be hardly any difficulty at all to extend those semantics to other kinds of methods. But we can't do it now; there are far too many backwards-compatibility issues to solve.
This design choice would also have the nice property that it would be a correct implementation of the "maybe monad".
But that's not the world we are in, and it's largely because these design considerations evolved over time, rather than being invented all at once. The next time you invent a new language, consider carefully how to represent nullability!
The where T : struct constraint lets one to limit the domain of acceptable type parameters to the set of value types (as compared to the superset of types including both value and reference types) only but also seems to forbid nullable types altogether although nullable doesn't necessarily mean a reference type in modern versions of C#.
What if I'd like to accept value types with added nullability like int?, DateTime? etc while rejecting natively-nullable reference types like string, IList etc? Is it possible to define the constraints this way? How if it is?
I am actually curious to learn to implement both the scenarios: when the type used as the parameter must be both value and nullable and when a nullable value type is to be accepted though as well as a non-nullable value type and I consider these related closely enough to excuse mentioning both so I'd appreciate a humble commentary about the second case and choose an answer including it as a better one (given another one is not going to be really better in other ways) if more than one answer will be submitted and I'll have to choose, but what I actually need right now is the first case (to always require a type that is both nullable and is a value type at the same time) and I also believe the second case is going to be pretty straightforward given the knowledge of the first, not to mention it is not a good manner to insist on gluing 2 questions into one so I will absolutely appreciate and accept an answer dealing with the first case only too.
You can't. Nullable<T> are not valid constraint for generics in C#.
When you try something like class X<T,U> where T : Nullable<U> you get following error:
'U?' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
If you need to accept both T and Nullable<T> as method parameters you can just provide overrides:
class X<T> where T : struct
{
public void R(T arg){ Console.WriteLine("Non nullable: {0}", arg);}
public void R(Nullable<T> arg){Console.WriteLine("Nullable: {0}", arg);}
}
And then you can call either version:
X<int> r = new X<int>();
r.R((int?)4);
r.R(4);
In your type deals with just Nullable values you can simply constraint to T:struct but everywhere inside your class use Nullable<T> for parameters and fields.
More discussions on particular aspects - C# generic type constraint for everything nullable and related questions.
It's not exactly what you want, but maybe you could use a type constraint of IConvertible? As an interface, it is nullable, and is implemented by Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char, and String.
class MyClass<T> where T : IConvertible
{
//Etc
}
In Nullable micro-optimizations, part one, Eric mentions that Nullable<T> has a strange boxing behaviour that could not be achieved by a similar user-defined type.
What are the special features that the C# language grants to the predefined Nullable<T> type? Especially the ones that could not be made to work on a MyNullable type.
Of course, Nullable<T> has special syntactic sugar T?, but my question is more about semantics.
What I was getting at is: there is no such thing as a boxed nullable. When you box an int, you get a reference to a boxed int. When you box an int?, you get either a null reference or a reference to a boxed int. You never get a boxed int?.
You can easily make your own Optional<T> struct, but you can't implement a struct that has that boxing behaviour. Nullable<T>'s special behaviour is baked into the runtime.
This fact leads to a number of oddities. For example:
C# 4: Dynamic and Nullable<>
C# Reflection: How to get the type of a Nullable<int>?
Cannot change type to nullable in generic method
And FYI there are other ways in which the Nullable<T> type is "magical". For instance, though it is a struct type, it does not satisfy the struct constraint. There's no way for you to make your own struct that has that property.
I found these two in the C# specifications:
The is operator works on T? as it would have on T, and the as operator can convert to nullable types.
Predefined and user-defined operators that operate on non-nullable value types are lifted to the nullable forms of those types.
Now, here are the features that I think are not limited to Nullable<T>:
The value in a switch can be of a nullable type. I don't think this counts, because switch also accepts user-defined implicit conversions that could be defined on a MyNullable type.
Nullable IDisposable types are supported, with a null check being inserted before the generated calls to Dispose(). I don't think this counts, because I could define MyNullable as a class and then it would be the same.
Here is what I am not sure about:
The specs mentions boxing/unboxing and implicit/explicit conversions, but I do not understand whether the same results can be achieved with a MyNullable.
C# lifts operators on nullable types. For example:
int? SumNullableInts(int? a, int? b)
{
return a + b;
}
You would have to do a lot of reflection work in MyNullable<T> to support that, and then the following would compile, where it shouldn't:
MyNullable<List<string>.Enumerator> SumNullableEnumerators(MyNullable<List<string>.Enumerator> a, MyNullable<List<string>.Enumerator> b)
{
return a + b;
}
I heard that the addition of Nullable<T> type to C# 2.0 need to revise CLR(runtime) a little, is this change necessary? Could it make the same goal if a new Nullable<T> generic class was added only?
Nullable isn't a generic class as you indicate, Nullable<T> is generic (it has a type parameter, T). That's why Nullable<T> only arrived in C# 2.0: it came with the addition of generics to the CLR.
You could do the same thing with a general Nullable, but you couldn't do things like this:
int? myInt = 123;
int result = myInt.Value;
You would instead have to:
int result = (int)myInt.Value;
...and it might not be type-safe, by that I mean what if myInt.Value is a string? The generic version, Nullable<T>, would only allow an int into the Value property.
I don't completely understand what you're asking, though.. "why are generic classes useful"?
If I understand you correctly, you are asking why can't it just be Type introduced in the framework library? but instead the CLR need to be changed?
Well based on my understanding Nullable is a special type, not quite like other container type. First it is actually a value type - defined as struct, not a class. Separately it allows to be assigned a value of null (for value type, that is a special case), plus it support the use of '?' and operator '??' which is all new. The Nullable also become part of the Common type system. So I guess from these perspective, the specification, compiler and CLR will need to be changed.
There are only two reasons I know of for the special handling of Nullable<T>:
To allow a typecast from null Object reference to a Nullable<T> with HasValue = false.
To allow a Nullable<T> where HasValue is false, to compare equal to null.
Frankly, think it would have been better to let Nullable<T> box like any other value type, and define Nullable<T>.Empty as a value which may be compared against (for those cases where one might want to compare against a variable that might be null or might hold a value). To my mind, there's no reason why Object.Equals should report that an "int?" which is equal to null is equal to a "long?" which is also equal to null. The first should be viewed as an empty int-sized box, and the latter as an empty long-sized box.
I'd like to have an integer variable which can be set to null and don't want to have to use the int? myVariable syntax. I tried using int and Int16 to no avail. Do I have to use int? myVariable?
I mentioned this because in Java there is both an 'int' type (a primitive) and 'Integer' (a reference type). I wanted to be sure that there isn't a built-in integer reference type that I could be using. I'll use 'int?' for what I'm doing.
For info, int? / Nullable<T> is not a reference-type; it is simply a "nullable type", meaning: a struct (essentially and int and a bool flag) with special compiler rules (re null checks, operators, etc) and CLI rules (for boxing/unboxing). There is no "integer reference-type" in .NET, unless you count boxing:
int i = 123;
object o = i; // box
but this creates an unnecessary object and has lots of associated other issues.
For what you want, int? should be ideal. You could use the long-hand syntax (Nullable<int>) but IMO this is unnecessarily verbose, and I've seen it confuse people.
Yes you should use nullable types
See Nullable
Nullable<int> Nullable<float>
or simply
int? float?
PS:
If you don't want to use ? notation or Nullable at all - simply use special structures for such a thing. For example DataTable:
var table = new DataTable();
table.Columns.Add('intCol',typeof(int));
var row = table.NewRow();
row['intCol'] = null; //
Nullable types are instances of the System.Nullable(T) struct.
Therefore int, int?, Nullable<int> are all value types, not reference types
Yes, it's the only way, as Int32/Int16/int is a primitive type (regardless of boxing/unboxing of these).
You will have to use a nullable type, i.e:
Nullable<int> or int?
The purpose of nullable type is, to enable you to assign null to a value type.
From MSDN:
Nullable types address the scenario where you want to be able to have a primitive type with a null (or unknown) value. This is common in database scenarios, but is also useful in other situations.
In the past, there were several ways of doing this:
A boxed value type. This is not strongly-typed at compile-time, and involves doing a heap allocation for every type.
A class wrapper for the value type. This is strongly-typed, but still involves a heap allocation, and the you have to write the wrapper.
A struct wrapper that supports the concept of nullability. This is a good solution, but you have to write it yourself.
You could use System.Nullable<int> if you hate ? so much.
Yes. That's why Microsoft added that. People were creating their own Nullable class so they included this pattern in .NET.
The <var>? syntax makes it nullable. If you dig a bit deeper, you'll see it's just a generic object that gets used.
If you want to do it like C++ you must use unsafe operations. Then, pointers like in C are available, but your code doesn't conform to CLR...
For using pure .NET without pointers, the ? is the way to go.