8

accidentally at work I wrote the following line of code:

string x = (object) null; 
// It was var x = (object)null and I changed from var to string instead of 
// object x = null;

This gave me a compilation error similar to this: Can't cast source type object to target type string

Why? Isn't null just a bunch of zeros pointing to "nowhere" memory address, no matter what the type is?

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • 1
    Why don't you assign `string x = string.empty;` ? – Shankar Narayana Damodaran Jan 25 '12 at 18:45
  • 5
    Why cast at all? `string x = null`.. – harold Jan 25 '12 at 18:45
  • 3
    Had you just said `string x = null;` you wouldn't have the issue. But that's not what you said. You said `string x = someObj;` where someObj is an `object` that just happens to be a null. As far as the compiler is concerned, you had an object reference that you were attempting to assign to a string, and that's not legal. – Anthony Pegram Jan 25 '12 at 18:45
  • @harold. You are right, It was by mistake, but it's still interesting me to know. – gdoron Jan 25 '12 at 18:48
  • You need an explicit cast to downcast an `object` reference to `string`. Therefore use `string x = (string)(object)null;`. Right? ;-) – Jeppe Stig Nielsen Jun 05 '12 at 07:08
  • @JeppeStigNielsen. Well... the question here is why it's needed... – gdoron Jun 05 '12 at 07:57
  • My comment was a kind of joke, because it's absurd to cast the `null` literal twice. The truth in the comment is that an expression of type `Object` cannot implicitly be cast to type `String` because that direction is a downcast. And in fact that is the answer to your question. Compare to this example: `string x = (object)"hello";` – Jeppe Stig Nielsen Jun 05 '12 at 20:29
  • @JeppeStigNielsen. Don't get me wrong, but I know this already. My question was about null string and null object. – gdoron Jun 05 '12 at 20:44
  • Would you have preferred it if `string x = (object)null;` was allowed but `string x = (object)"hello";` was disallowed? – Jeppe Stig Nielsen Jun 05 '12 at 21:21
  • @JeppeStigNielsen. I'm afraid we're getting to chatty about an old post. Regarding to your question, YES, this is what my question was. – gdoron Jun 06 '12 at 06:28

7 Answers7

23

The problem is not the casting of null, it's that object isn't assignable to string. This works fine

string x = (string)null;

The reason this works if you remove the cast (string x = null) is laid out in section 2.4.4.6 of the C# Language Specification

The null-literal can be implicitly converted to a reference type or nullable type

The moment you introduce a cast ((object)null) you no longer have a null literal. Instead you have a value of type object. It's essentially no different than

object temp = null;
string x = temp;
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • I know how I can fix it. I'm asking What is the difference between null object and null string? – gdoron Jan 25 '12 at 18:46
  • you are still thinking of it as "null" but you've said its a particular type of object. – Keith Nicholas Jan 25 '12 at 18:47
  • 6
    @gdoron *What is the difference between null object and null string?* Their types, which makes all the difference in the world. Similar to asking how are `(float)3` and `(int)3` different. – Yuck Jan 25 '12 at 18:47
  • @gdoron I updated my answer a bit to explain the semantics a bit more here – JaredPar Jan 25 '12 at 18:48
  • @Yuck: That demonstrates an interesting case. "uint x = (int)0;" would succeed even though int is not implicitly convertible to uint. – Eric Lippert Jan 25 '12 at 18:57
  • laid out in section 2.4.4.6 what is this? – Afnan Bashir Jan 25 '12 at 19:05
  • @EricLippert Strange, and I've asked that as a new question if you don't mind answering - http://stackoverflow.com/questions/9008637/why-does-this-implicit-conversion-work – Yuck Jan 25 '12 at 19:06
  • 1
    @Lagrangian it's section 2.4.4.6 of the C# 3.5 language specification. It can be downloaded from a link on this page http://msdn.microsoft.com/en-us/library/ms228593.aspx – JaredPar Jan 25 '12 at 19:10
11

The question here is basically "why does the compiler not take into account the fact that it knows that the assigned value is a constant reference known to be null?"

The answer is: why should it? What's the compelling benefit of taking that information into account? You deliberately said "I want this expression to be treated as though it were of type object", and you can't assign a value of type object to a variable of type string. What's the benefit of allowing that in this case?

The code seems to me to be highly likely to be a bug; surely the compiler should be telling you about it rather than allowing it.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thanks, Got it. But is it true that a null `object` and a null `string` refer to the same memory address? – gdoron Jan 25 '12 at 19:00
  • 6
    @gdoron: memory address? **What is this thing you call a "memory address?"** The null *reference* is a *reference*. In practice, sure, a reference is typically implemented as an address. But it need not be; references could be handles into a big table maintained by the garbage collector, for example. Don't think of references as addresses; think of them as the abstract notion of referencing something. – Eric Lippert Jan 25 '12 at 19:05
  • 9
    @gdoron: Now that we have that out of the way: is it the case that a null object and a null string refer to *the same thing*? No, of course not. **They don't refer to anything.** Think about it this way. I have a piece of paper labelled "favourite ice cream". It is blank. You have a piece of paper labelled "favourite movie". It is also blank. Do those two pieces of paper "refer to the same thing"? Of course not. Neither of them refers to *anything*, so there is no *same thing* that they both refer to! – Eric Lippert Jan 25 '12 at 19:07
  • 4
    Or, even better: my paper says "None, because I don't have a favourite ice cream" and yours says "None, I don't have a favourite movie". Now do the contents of those two papers refer to "the same thing"? Just try to show me the *thing* that both these pieces of paper are referring to! "Nothing" is by definition *not a thing*. – Eric Lippert Jan 25 '12 at 19:42
  • 4
    The more I read your's answers and blog post, I think you really should write a book about the meaning of life. (or the meaning of null...) – gdoron Jan 25 '12 at 19:46
  • @gdoron you might have been confused by the old NULL macro in C, which was literally a pointer to address 0. i.e. ((void*)0). – Eren Ersönmez Jan 27 '12 at 07:18
5

Isn't null just a bunch of zeros pointing to "nowhere" memory address, no matter what the type is?

That's all it is in a weakly-typed language like C or C++.

In C#, a reference's type is an integral part of its identity. (string)null is not the same thing as (object)null because one is a string and one is an object.

Furthermore, in C# null doesn't really have a numeric equivalent. References in C# are not the same thing as pointers and, semantically speaking, they do not have an associated memory address. null simply means that the reference does not point to an object, and a null reference's internal representation is an implementation detail.

Sean U
  • 6,730
  • 1
  • 24
  • 43
3

It needs to be assignable - even if it may seem it's "the same null" and it shouldn't matter, the compiler still upholds the type. One advantage of that is in resolving overloads:

void Foo(object bar) { ... }
void Foo(string bar) { ... }

Foo((object)null); // will call the former
Foo((string)null); // will call the latter
JimmiTh
  • 7,389
  • 3
  • 34
  • 50
  • 3
    An interesting answer! But let's suppose that (object)null was implicitly convertible to string. The overload resolution algorithm would still choose the object version because that was an *exact* type match. The overload resolution algorithm always says that an identity conversion is better than any other conversion when trying to decide which of two methods is better. – Eric Lippert Jan 25 '12 at 18:53
  • I should visit your blog more (and reread Jon Skeet). After 8 years with C#, I still had to check the above code in VS to see if it actually worked. ;-) – JimmiTh Jan 25 '12 at 19:01
2

maybe object x = (string) null; that might work,, but why would you?

because object can hold a string,, but a string cant hold an object

string is inherited from object,, not the other way around.

SynerCoder
  • 12,493
  • 4
  • 47
  • 78
0

You can assign null to any variable of reference type without casting anything:

String x = null;
Mithrandir
  • 24,869
  • 6
  • 50
  • 66
0

Every class has, a list of definitions for:

Constructors
Destructors
Fields
Methods
Properties
Indexers
Delegates
Events
Nested Classes

Object is a generic type, because every class is inherit from it but not the other way. Those definitions are not the same for every class, so your compiler can decide which types you can assign/cast to each other.

Then you doing: string x = (object)null;

Compiler doesn't care that value you are trying to assign to your x in first place, but it's checks the type definitions of string and just don't let you to shoot your own leg, and generates an error, because it's a type mismatch.

gdoron
  • 147,333
  • 58
  • 291
  • 367
0xbadc0de
  • 3,805
  • 3
  • 22
  • 14