Nulls not missing anymore
In the past, I have talked about how your feedback is a critical part of us building the right product. Recently, we took a big DCR (Design Change Request) into Visual Studio 2005 that was in response to your feedback. This was a hard call, because it was a big change that touched many components including the CLR. Nonetheless, we decided to take this change at this late stage in the game because a) this was the right product design and I always believe in optimizing for the long-term and b) I had confidence in the team(s) to be able to get this work done in time for Visual Studio 2005. This is a classic example of how we are listening to your feedback that results in a better product for all of us.
This particular work-item relates to the new System.Nullable data type included as part of the .Net Runtime in Visual Studio 2005. If you want some context on what the Nullable type is all about, you can read this article in MSDN.
The August CTP for Visual Studio 2005 that is coming out in the next week or so will have this new implementation for the System.Nullable data type.
The C# team used the following example to illustrate why our original implementation could be confusing and how we changed support for Nullable type to make it more elegant, easy to understand and use for application developers.
We designed the Nullable type to be the platform solution, a single type that all applications can rely on to uniformly represent the null state for value types. Languages like C# went ahead and built in further language features to make this new primitive feel even more at home. The idea was to blur the subtle distinction between this new value-type null and the familiar reference-type null. Yet, as it turns out, enough significant differences remained to cause quite a bit of confusion.
We soon realized the root of the problem sat in how we chose to define the Nullable type. Generics were now available in the new runtime and it seemed quite simple to use this feature to build up a new parameterized type that could easily encode both a value type and an extra flag to describe its null state. And by defining the Nullable type also as a value type we retained both the runtime behaviors and most of the performance of the underlying primitive. No need to special case anything in the runtime. We could handle it all as just an addition to the runtime libraries, or so we thought.
As several of you pointed out, the Nullable type worked well only in strongly-typed scenarios. Once an instance of the type was boxed (by casting to the base ‘Object’ type), it became a boxed value type, and no matter what its original ‘null’ state claimed, the boxed value-type was never null.
int ? x = null;
object y = x;
if (y == null) { // oops, it is not null?
...
}
It also became increasingly difficult to tell whether a variable used in a generic type or method was ever null.
void Foo<T>(T t) {
if (t == null) { // never true if T is a Nullable<S>?
}
}
Clearly this had to change. We had a solution in Visual Studio 2005 Beta2 that gave users static methods that could determine the correct null-ness for nullable types in these more or less ‘untyped’ scenarios. However, these methods were costly to call and difficult to remember to use. The feedback you gave us was that you expected it to simply work right by default.
So we went back to the drawing board. After looking at several different workarounds and options, it became clear to all that no amount of tweaking of the languages or framework code was ever going to get this type to work as expected.
The only viable solution was one that needed the runtime to change. To do that, it would require concerted effort by a lot of different teams working under an already constrained schedule. This was a big risk for us because so many components and products depend on the runtime that it has to be locked down much sooner than anything else. Even a small change can have significant ripple effects throughout the company, adding work and causing delays. Even the suggestion of a change caused quite a bit of turmoil. Needless to say, many were against the proposal for very credible reasons. It was a difficult decision to make.
We were fortunate that so many here were willing to put in the extra work it took to explore the change, prototyping it and testing it, that a lot of the uncertainty and angst was put to rest, making the decision to go ahead all that much easier.
The outcome is that the Nullable type is now a new basic runtime intrinsic. It is still declared as a generic value-type, yet the runtime treats it special. One of the foremost changes is that boxing now honors the null state. A Nullabe int now boxes to become not a boxed Nullable int but a boxed int (or a null reference as the null state may indicate.) Likewise, it is now possible to unbox any kind of boxed value-type into its Nullable type equivalent.
int x = 10;
object y = x;
int ? z = (int?) y; // unbox into a Nullable<int>
Together, these changes allow you to mix and match Nullable types with boxed types in a variety of loosely typed API’s such as reflection. Each becomes an alternative, interchangeable representation of the other.
The C# language was then able to introduce additional behaviors that make the difference between the Nullable type and reference types even more seamless. For example, since boxing now removes the Nullable wrapper, boxing instead the enclosed type, other kinds of coercions that also implied boxing became interesting. It is now possible to coerce a Nullable type to an interface implemented by the enclosed type.
int ? x = 0;
IComparable<int> ic = x; // implicit coercion
I sincerely hope these changes were worth the effort and that application builders will find the definition of a common representation for null value types beneficial for the development of their products.
Namaste!
Comments
Anonymous
August 11, 2005
THANK YOU THANK YOU THANK YOUAnonymous
August 11, 2005
One question - are method calls on nullable types seamless too in C#?
For example is it possible to do this:
DateTime? dt = DateTime.Now;
Console.WriteLine(dt.ToShortDateString());
(Even without this it's an AWESOME and incredible improvement - I'm only even mentioning it because this change too would be impossible to add in a later version if it's not done now, in case the value type being nulled has a Value or HasValue property of its own)Anonymous
August 11, 2005
That's great to see the team listen to feedback and implement that at this stage of the product.Anonymous
August 11, 2005
Lots happened with Nullable pretty late in the game and it sure was a big effort by a bunch of people...Anonymous
August 11, 2005
Lots happened with Nullable pretty late in the game and it sure was a big effort by a bunch of people...Anonymous
August 11, 2005
Despite the investment of time and money Microsoft has made in the name of community, there are those...Anonymous
August 11, 2005
Looks nice, but does the following compile and work as intended?
object x = null;
int? y = (int?) x;
if (y == null) {
Console.WriteLine("It works as intended.");
}Anonymous
August 11, 2005
Sounds good. Somathat similar to ideas I've proposed 8 months ago at http://lab.msdn.com/productfeedback/viewfeedback.aspx?feedbackid=FDBK19417
But will this print true at some time ?
int? a = null;
int? b = null;
Console.WriteLine(a >= null); // It now print False
Console.WriteLine(a >= b); // Also print False
(reported ~2 months ago at http://lab.msdn.com/productfeedback/viewfeedback.aspx?feedbackid=FDBK30893 )Anonymous
August 11, 2005
Efter at en del har påpeget en del designmæssige problemer med System.Nullable typer i .NET 2.0, har...Anonymous
August 12, 2005
This is fantastic. Special boxing rules for nullable types is an excellent idea. I'm impressed that so much energy is put into making the framework homogeneous throughout - makes my life much easier. Thanks a bunch.Anonymous
August 12, 2005
The comment has been removedAnonymous
August 12, 2005
This is one of those tough changes that will pay dividends for a long time. Simply put the "right choice."
Slightly off topic though how does this change affect the future of System.DBNull as a data type? Will it be deprecated in the near future? It does appear as though it's no longer needed.Anonymous
August 12, 2005
The comment has been removedAnonymous
August 12, 2005
New Nullable<> runtime fix for .NET 2.0.Anonymous
August 12, 2005
How does this affect the recently-adopted ECMA specifications for 2.0?Anonymous
August 12, 2005
In Beta 1, it annoyed me terribly that nullable types weren't CLS compliant. In Beta 2, it annoyed me that nulls didn't work as expected. It's great to know that it will have been done right for the final release. Great Job!
One more question though:
You exlained earlier that the following code works because the compiler knows how to interpret the null-check:
int? a = null;
if (a == null)
{
Console.WriteLine("yes");
}
I was wondering how intelligent this check is. For example, will this work?
int? a = null;
if (Object.Equals(a, null))
{
Console.WriteLine("yes");
}Anonymous
August 12, 2005
Michael, the great thing about the new nulls is that yes Object.Equals(a,null) succeeds. It does this because when a is boxed, it becomes a null reference, and every schoolkid knows null == null. :-)Anonymous
August 12, 2005
Soma explains the changes to the .Net runtime to fix the problems with Nullable&lt;T&gt;.
http://blogs.msdn.com/somasegar/archive/2005/08/11/450640.aspx...Anonymous
August 12, 2005
That's great news Matt. So, I can finally get rid of this terrible piece of code I wish I had never written back in Beta 1. :-)
INullableValue isNullable = myObject as INullableValue;
if (isNullable != null)
{
blnNull = !isNullable.HasValue;
}
else
{
blnNull = (myObject == null);
}Anonymous
August 12, 2005
Those changes were sincerely worth the effort. Thanks.Anonymous
August 12, 2005
As many of you&nbsp;may know, we recently announced a pretty big change to the C# 2.0 language.&nbsp;...Anonymous
August 12, 2005
Anders:
object x = null;
int? y = (int?) x;
if (y == null) {
...Console.WriteLine("It works as intended.");
}
Yes, this works as intended.Anonymous
August 12, 2005
The comment has been removedAnonymous
August 12, 2005
The comment has been removedAnonymous
August 12, 2005
Tra ieri e
oggi sono usciti due post (Joe Duffy e Somasegar) a proposito
di un cambiamento nella...Anonymous
August 13, 2005
I saw from Soma's blog that VS is taking a DCR to fix the issues about Nullable types that is being talked...Anonymous
August 13, 2005
int? is a nullable value type
int is a non-null value type
Please, please, please really make the behaviour consistent:
Blob? a nullable reference type
Blob a non-null reference type
Like http://nice.sourceforge.net/manual.html#optionTypesAnonymous
August 13, 2005
Soma has a good post on a late change we made to Nullable&lt;T&gt; for Whidbey, aka VS 2005 and .NET...Anonymous
August 13, 2005
TAG, I think you misread CyrusN. He didn't say that it wouldn't compile, but rather that it would compile with the semantics that you and I expect:
int? x = null;
int? y = null;
bool a = (x == y); // true
bool b = (x == y) || (x < y); // true;
bool c = (x == y) || (x > y); // true;
bool d = (x <= y); // currently false
bool e = (x >= y); // currently false
It seems very odd that b != d and c != e, when this would hold true if x and y were not nullable.
Vance, I respectfully disagree that keeping the current semantics for >= and <= is correct for nullable type, but based upon the feedback on my defect, it seems that either only TAG and I have run into this problem or everyone else agrees with your decision.
Either way, I'd still like a better explanation from the C# Team of why you feel that breaking the meaning of >= and <= is more desirable than fixing this problem.Anonymous
August 13, 2005
Soma (my boss's boss's boss's boss) recently blogged about how the CLR took a major change to fix Nullable.&nbsp;...Anonymous
August 13, 2005
Good job, good job. Catch them before I hit. Can you please make another breaking change:
Fix the following ambiguity:
Point p = new Point();
Point x = p;
x.x = 3;
Now, is p.x also 3? Depends on whether the Point type is structure or class, right? But if you had different syntax at some point we could tell.
Regards,
SuaviAnonymous
August 13, 2005
Good job, good job. Catch them before I hit. Can you please make another breaking change:
Fix the following ambiguity:
Point p = new Point();
Point x = p;
x.x = 3;
Now, is p.x also 3? Depends on whether the Point type is structure or class, right? But if you had different syntax at some point we could tell.
Regards,
SuaviAnonymous
August 14, 2005
<quote>
Good job, good job. Catch them before I hit. Can you please make another breaking change:
Fix the following ambiguity:
Point p = new Point();
Point x = p;
x.x = 3;
Now, is p.x also 3? Depends on whether the Point type is structure or class, right? But if you had different syntax at some point we could tell.
Regards,
Suavi
</quote>
PLEASE, PLEASE don't change anything to deal with Suavi's concerns.Anonymous
August 15, 2005
Suavi wrote:
> Now, is p.x also 3? Depends on
> whether the Point type is structure or
> class, right? But if you had different
> syntax at some point we could tell.
Suavi, please do all of us a favor and learn about the different semantics of the assignment operator on reference types and value types before posting stuff like this. Thank you.Anonymous
August 15, 2005
No, Sauvi's right - mutable value types are horribly confusing. He's wrong to suggest it be "fixed", because that would be completely backwards-incompatible which is a cure far worse than the disease, but it is a bad feature of the language.
IMHO, value types should simply never be mutable, which makes this point moot. Fortunately, the ones I usually use (int, bool, char, DateTime, and enums, and in Whidbey Nullable<T>) are all immutable and I never have to deal with this.
If I had been designing C# I'd have endeavored to find a way to forbid mutable value types entirely, or at least required some special effort to support them, because you really need to know what you're doing to use them intelligently.Anonymous
August 15, 2005
You might find mutable value types confusing, but you are free to provide your own readonly implementations. Sauvi's whole argument stems from his intention to change Point.X after creation - so your suggestion of making value types inherently immutable won't provide a remedy in his case.
Still, I do understand your reasoning in general.
Cheers!Anonymous
August 15, 2005
Arno, that wasn't how I interpreted Sauvi's post. I didn't see any desire for one behavior or the other; I interpreted his complaint as the fact that simply looking at his code sample, you don't know whether p.x was changed or not. You have to know what type Point refers to and whether it's a class or a struct.
In my ideal world the problem wouldn't exist because if Point were a value type, his code would fail to compile - x.x is not writable. You'd have to write x = new Point(3, p.y) or something, and then it's utterly clear that p is unaffected.Anonymous
August 15, 2005
> int? x = null; int? y = null;
>
> bool a = (x == y); // true
> bool b = (x == y) || (x < y); // true
> bool c = (x == y) || (x > y); // true
> bool d = (x <= y); // currently false
> bool e = (x >= y); // currently false
>
> It seems very odd that b != d and c != e, when this would
> hold true if x and y were not nullable.
The reason this is bizarre is because it is contrary to the way that database nulls operate. With database nulls, (x == y) would return unknown when both x and y were null. Obivously, this greatly complicates the problem because of something like the following:
bool a = false;
int? x = null;
int? y = null;
if (a == (x == y))
Console.Writeline("Yes");
else
Console.Writeline("No");
In the database world, we would get "No". However, if (x == y) literally equates to false, then we'll get (false == false) which will equate to true and we'll get "Yes".
That said, I would still think that the following would be a more conservative approach:
int? x = null;
int? y = null;
bool a = (x == y); // false (unknown)
bool b = (x == y) || (x < y); // false (unknown)
bool c = (x == y) || (x > y); // false (unknown)
bool d = (x <= y); // false (unknown)
bool e = (x >= y); // false (unknown)
The catch is that the system would have to differeniate between:
Nullable type equal to null == Nullable type equal to null
as opposed to:
Null reference type == Null reference type
Ideally, some rule such as the following would be implemented:
Nullable Type <boolean op> Anything = false in all circumstances.Anonymous
August 15, 2005
Acording to this post&nbsp;Microsoft has decided to change the nullable types implementation for the...Anonymous
August 15, 2005
Thomas:
Partially agree with you.
Instead of returning bool - it was possible to return bool? as result of operators with nullable types.
This will allow to type pretty clear expressions like a:
if ( (a>=b) ?? false) {
}
But the more I think about this issue - the more I do not care about it ;-)
All my problems can be solved with a little trick - usage of ! (negation operator).
I.e. a>=b , a<=b and !(a>=b), !(a<=b) are 4 totally different expressions you can choice from. This will cover all situations developers need.Anonymous
August 16, 2005
So much going on.....Had a week and a half of vacation which was nice. It was nice to get back to see...Anonymous
August 16, 2005
I suppose I'm not clear on what is fixed in the August CTP nor am I sure why it was designed this way. As Erik pointed out earlier
int? x;
int? y;
bool a == ((x < y) || (x == y));
bool b == (x <= y);
a != b when x and y are null. This is what I call a "gotcha." It is an easily forgettable, unintuitive difference that no developer would ever expect. I was always taught that <= is literally short hand for the longer version of the equation (ie. < || ==). However, this would obviously contradict that.
Does this work the same in the August CTP and why?
TAG, what is really going on is that a <= b and ((a < b) || (a == b)) are being treated as two totally different expressions that being evaluated completely differently. I would argue that the former (<=) is being evaluated incorrectly.Anonymous
August 16, 2005
The comment has been removedAnonymous
August 16, 2005
When I first heard this, I thought it would be great to move away from the awkwardness of sqltypes. Reading the actual summary though, I'm unsure of the benefit.
If I've got this right, I can now do:
int? x = null;
if(x == null)
Console.WriteLine("GREAT!");
But:
int? x = 3;
int y = 3;
if(x.ToString() == y.ToString())
Console.WriteLine("GREAT!");
This will generate a compile error? (since I left out .Value)
So basically, I now have the choice of typing ".IsNull" or " == null"... Surely there's more to it than that...?
No offence, but if all this effort was put in to remove special cases from nullable types, why was the SINGLE "null" value fingered out (which we STILL have to check for) rather than the INFINITY of "everything else"?
I'd much rather have:
int? x=3;
Object y;
if(x.IsNull)
y = null;
else
y = Item[x];
than
if(x == null)
y = null;
else
y = Item[x.Value];
And is it just me, or without both, is there really no real benefit over sqltypes anyhow? I mean, I do a lot of this in v1.1:
if(x.IsNull)
TextBox1.Text = "";
else
TextBox1.Text = x.Value.ToString();
I'd much rather both cases be addressed, and be able to do something like:
TextBox1.Text = x.ToString();
THAT would be an improvement.
(And no, I don't think "null" is a valid response for null.ToString() either. :P But that's not really at issue here.)Anonymous
August 17, 2005
With mixins is it going to be possible to have Nullable<T> to inherit from T and thus enable
DateTime? d = DateTime.Now;
Console.WriteLine(d.ToShortDateString());
Is it being considered for a mixin at all?Anonymous
August 19, 2005
>> The core problem that causes this in the first place is that the syntax for value types and reference types in C# was overloaded.
Yes, which is what Sauvi was trying to point out (perhaps not as well as he could have).
C# wonderfully got rid pointer syntax and memory mangagement (not just responsibility to deallocate but also stack vs. heap), and so it is within reach of all vb programmers. I do have to say, it's nice to just "." everything.
But surprise...pointers can be null and so having pointers meant having nullable objects.Anonymous
August 19, 2005
>> Yes, which is what Sauvi was trying to point out (perhaps not as well as he could have).
>> C# wonderfully got rid pointer syntax and memory mangagement (not just responsibility to deallocate but also stack vs. heap), and so it is within reach of all vb programmers. I do have to say, it's nice to just "." everything.
>> But surprise...pointers can be null and so having pointers meant having nullable objects.
If you read my comment again you'll note I don't disagree with the new syntax, nor do I have any problem with nullable types (and in fact consider them a critical addition to C# to make it competitive against MC++). What I did ask is why that new syntax required corresponding new backend support (which is what much of this blog post was about).
Original Blog Quote: "We could handle it all as just an addition to the runtime libraries, or so we thought." ... "The only viable solution was one that needed the runtime to change."
My Response Quote: "Umm... why would this require a runtime change?"
Yes, it requires modifying the compiler, as I said the core problem is a syntax issue. No, it shouldn't require modifying the runtime to add special support for "nullable" types. As I pointed out, I might be mistaken about something, but .NET already had support for managed pointers to value types, and in fact MC++ could already use this. C#'s syntax simply chose not to expose that.
The '?' syntax is fine. That didn't concern me. I even dedicated a paragraph to how to make this syntax work with managed pointers.
My Response Quote: "When you declare 'int?' it should declare a managed pointer to a 'System.Int32'."Anonymous
August 19, 2005
Jay, I was not disagreeing with anything you said. Quite the contrary!
I didn't comment on the "?" syntax, which actually I don't care for, but I'll get over that.Anonymous
August 19, 2005
"But surprise...pointers can be null and so having pointers meant having nullable objects"
And pointers types can also be non-nullable!
Like Nice
http://nice.sourceforge.net/manual.html#optionTypes
Like Spec#
http://research.microsoft.com/specsharp/Anonymous
August 19, 2005
얼마전에 Microsoft의 Developer Division 대빵인 Somasegar가 Nulls not missing anymore라는 글로 Nullable Types의 DCR(Design...Anonymous
August 19, 2005
얼마전에 Microsoft의 Developer Division 대빵인 Somasegar가 Nulls not missing anymore라는 글로 Nullable Types의 DCR(Design...Anonymous
August 20, 2005
얼마전에 Microsoft의 Developer Division 대빵인 Somasegar가 Nulls not missing anymore라는 글로 Nullable Types의 DCR(Design...Anonymous
August 21, 2005
얼마전에 Microsoft의 Developer Division 대빵인 Somasegar가 Nulls not missing anymore라는 글로 Nullable Types의 DCR(Design...Anonymous
August 21, 2005
Data Source Controls (Part 3 - Asynchronous Data Access)
Data Source Controls (Part 4 - [I guess,...Anonymous
August 23, 2005
You might have already read this: VS2005 made the last-minute DCR related to boxed Nullable&lt;T&gt;....Anonymous
August 24, 2005
CLR took a DCR some time back on how nullable types are implemented. See here and here&nbsp;to find out...Anonymous
August 24, 2005
CLR took a DCR some time back on how nullable types are implemented. See here and here&nbsp;to find out...Anonymous
August 24, 2005
CLR took a DCR some time back on how nullable types are implemented. See here and here&nbsp;to find out...Anonymous
August 24, 2005
CLR took a DCR some time back on how nullable types are implemented. See here and here&nbsp;to find out...Anonymous
August 24, 2005
CLR took a DCR some time back on how nullable types are implemented. See here and here&nbsp;to find out...Anonymous
August 30, 2005
The Microsoft Visual Studio 2005 August CTP is now available on the MSDN subscriptions site at http://msdn.microsoft.com/subscriptions. MSDN subscribers can download these bits and test out the new Nullable feature discussed on this blog.
- Microsoft Developer Division Release TeamAnonymous
August 31, 2005
With Visual Studio 2005, the CTP August 2005 has new runtime features for Nullable types.&nbsp;
Nullable...Anonymous
September 01, 2005
I agree that Acrylic is going to be a wonderful product once in the marketplace. At the same time I have used Adobe Expression and feel this is an underrated product. Please feel free to contact me at www.pop2go.com I am the programmer there.Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 08, 2005
Our VP, Soma posted about the last minute changes to Nullable&lt;T&gt; in Visual Studio 2005. The changes...Anonymous
September 15, 2005
I've totally&nbsp;lost my voice (quite literally cannot talk) here at the PDC and had to miss the Ask...Anonymous
January 26, 2007
Tra ieri e oggi sono usciti due post ( Joe Duffy e Somasegar ) a proposito di un cambiamento nella gestioneAnonymous
July 04, 2007
java C# languagesAnonymous
April 16, 2008
l need your help.solution to this problem. quetion;(1) console.write(a/b) (2) console.write(b/a). with the reason to support the answer. in visual basic programAnonymous
April 18, 2008
Israel - Take a look at the code below: Dim a As Double Dim b As Double Console.Write(a / b) Console.Write(b / a) The output here will be NaN for both operations. The reason is that in VB all variable declarations are implicitly initialized. In the case of double the default initialization is to 0. Hence 0/0 is NaN (Not a Number) With Nullables things are slightly different. If a and b are both Nullable types the result is different. Dim a As Double? Dim b As Double? Console.Write(a / b) Console.Write(b / a) The output will be empty string in both cases. The reason is that Nullable types by definition have no initialization. Thus Null/Null = Null and Null.ToString is empty string hence no output. Does this answer your question?Anonymous
June 28, 2008
By now, you have likely read Somasegar's blog entry on nullable types in VS 2005. You know that nullable types are now recognized by the CLR and no longer implement INullableValue. What you may not have realized is that nullable types no longer implementAnonymous
May 29, 2009
PingBack from http://paidsurveyshub.info/story.php?title=somasegar-s-weblog-nulls-not-missing-anymoreAnonymous
June 19, 2009
PingBack from http://debtsolutionsnow.info/story.php?id=6472