'null' references

J

Jon Skeet [C# MVP]

valentin tihomirov said:
As explained in "Using pointers vs. references"
http://groups.google.ee/group/borland.public.delphi.objectpascal/brow
se_thread/thread/683c30f161fc1e9c/ab294c7b02e8faca#ab294c7b02e8faca ,
the pointers are allowed to be null, while references must refer an existing
variable of required type. The null is normally used for making optional
parameters. But there is no way to pass null reference in C#. Something is
missing.

That's using Delphi terminology, which isn't terribly helpful in C#.

In C# null *is* a reference:

<quote>
A reference type value is a reference to an instance of the type, the
latter known as an object. The special value null is compatible with
all reference types and indicates the absence of an instance.
</quote>

and

<quote>
The null literal (§9.4.4.6) evaluates to the null value, which is used
to denote a reference not pointing at any object or array, or the
absence of a value. The null type has a single value, which is the null
value. Hence an expression whose type is the null type can evaluate
only to the null value. There is no way to explicitly write the null
type and, therefore, no way to use it in a declared type.
</quote>

Now, given that, I don't actually see what you're trying to do. You can
pass null as an argument without an problems. Try to describe it in
terms of achieving a goal, rather than being like another language.
 
J

John Brown

As explained in "Using pointers vs. references"
http://groups.google.ee/group/borla...0f161fc1e9c/ab294c7b02e8faca#ab294c7b02e8faca ,
the pointers are allowed to be null, while references must refer an
existing variable of required type. The null is normally used for making
optional parameters. But there is no way to pass null reference in C#.
Something is missing.

Yes, for those coming from the C++ world such as myself it's an annoyance
(since you can't pass null for "out" or "ref" parameters that you're not
interested in). Other issues include a lack of "const-correctness", no
covariant return types (a must in OOP), the need to initialize all variables
all the time (even though it's not actually required on occasion - you still
have to do it though), and other pet peeves. "C#" certainly has benefits
that C++ can learn from but C++ still has much to teach as well. Part of the
problem with "C#" and .NET in general was its rush to get to market. This
likely resulted from the pressure MSFT was feeling to counter Java before it
was too late. It shows given how generics were introduced only in 2.0 for
instance (they should have been implemented from the outset) and many
classes are now obsolete or deprecated as result (for all intents and
purposes). .NET is therefore forced to carry this excess baggage around
including some ugly class derivations to support both the old interfaces and
their generic counterparts (or consider the even more insidious/pervasive
use of "object" which isn't type-safe and therefore a notorious source of
problems). Most of this will now be around permanently of course which shows
what happens when a language is pushed out the door too soon.
 
V

valentin tihomirov

That's using Delphi terminology, which isn't terribly helpful in C#.
Now, given that, I don't actually see what you're trying to do. You can
pass null as an argument without an problems. Try to describe it in
terms of achieving a goal, rather than being like another language.

I do not understand why the terminology, which matches C very well is so
inconsistent with C#. Btw, which language do information technology
scientins base their theories on? Do they fix on some concrete language
explaining their discoveries? I just ask for some typical thing how to do it
in C# refering some other langs as examples.


In C# null *is* a reference:

This is great, but the following code fails to compile:
func(null);
as well as
func(ref null);
 
A

Alberto Poblacion

valentin tihomirov said:
This is great, but the following code fails to compile:
func(null);
as well as
func(ref null);

The first one does compile if the argument to func is a reference type:

void func(object x) {}
....
func(null); //OK

The second one requires a variable:

void func(ref object x) { if (x==null) x=new myclass(); }
....
object y = null;
func (ref y);
//now y contains a reference to a myclass object
 
V

valentin tihomirov

object y = null;
func (ref y);
//now y contains a reference to a myclass object

A reference to the special NULL object is not the same thing as the
zero-pointer, which refers nothing (zero address is invalid). That is why I
point out that pointer argument itself is allowed to be zero while reference
is not. A reference must always refer something (whether a valid object or
'null' object).

Thanks for the hint. I suppose it is the supposed way to do it in C#. It has
two disadvantages though: 1) you must declare a bogus reference variable;
and 2) initialize it before passing to the function, where you could just
pass a 0 right away. Furthermore, it prevents you from using 'out'
arguments.

Actually, pointers are needed to write directly to the address they points
to. Using reference to the bogus null-object, which we leave unmodifed when
assign a new value to the reference to return. This makes passing the bogus
value by reference a bit nonsenes. Pointers reach the same effect without
creating any bogus objects, which as stated above has additional usage
advantages.

Peahaps, too much words for the issue. Yet, I do not know any places where
it is discussed.
 
P

Peter Duniho

A reference to the special NULL object is not the same thing as the
zero-pointer, which refers nothing (zero address is invalid).

Frankly, I don't see how it's all that different at all. There are some
minor semantic differences, but for all intents and purposes a "null" in
C# is pretty much the same as a "null" in C++.
That is why I
point out that pointer argument itself is allowed to be zero while
reference
is not. A reference must always refer something (whether a valid object
or
'null' object).

You can't use a null for a reference parameter in C++ either. The
following generates a compile error, just as the "ref" parameter example
you gave for C# does:

void Func(int &i)
{
}

void Caller()
{
Func(nullptr);
}
Thanks for the hint. I suppose it is the supposed way to do it in C#. It
has
two disadvantages though: 1) you must declare a bogus reference variable;
and 2) initialize it before passing to the function, where you could just
pass a 0 right away. Furthermore, it prevents you from using 'out'
arguments.

Again, how is this difference from passing by reference in C++?
Actually, pointers are needed to write directly to the address they
points
to.

In C#, a reference is needed to write directly to the address it points
to. Same thing.
Using reference to the bogus null-object, which we leave unmodifed when
assign a new value to the reference to return.

I don't understand this statement. How can you leave something unmodified
while at the same time assigning a new value?
This makes passing the bogus
value by reference a bit nonsenes. Pointers reach the same effect without
creating any bogus objects, which as stated above has additional usage
advantages.

The only real difference I see is that if you pass a pointer to a
_pointer_ in C++, that allows you to have similar behavior to (but not
exactly the same as) passing by reference, while at the same time allowing
for the parameter to be optional. For example:

void Func(int *pi)
{
if (pi != null)
{
*pi = <some result goes here>;
}
}

void Caller()
{
int i;

Func(&i);
Func(null);
}

However, I fail to see how this is really much of an advantage. In C# you
would be required to create a dummy local that you would just ignore. In
C++ you have to have code in the function itself to check whether the
parameter is null. Either way, there's extra code, and in the C# case it
eliminates the chance of a null-dereference run-time error (in C++, if you
forget to check for the parameter being null, you can crash).

I see this as _better_, not worse.
Peahaps, too much words for the issue. Yet, I do not know any places
where
it is discussed.

Frankly, after having seen several of these "rants" from you, I am left
wondering why you bother to use C#. I don't really think you understand
the issues you're talking about anyway, but even assuming you do, it seems
to me that if you feel C++ is so much better suited to your needs, then
that's the language you ought to be using.

Pete
 
P

PS

valentin tihomirov said:
A reference to the special NULL object is not the same thing as the
zero-pointer, which refers nothing (zero address is invalid). That is why
I point out that pointer argument itself is allowed to be zero while
reference is not. A reference must always refer something (whether a valid
object or 'null' object).

Thanks for the hint. I suppose it is the supposed way to do it in C#. It
has two disadvantages though: 1) you must declare a bogus reference
variable; and 2) initialize it before passing to the function, where you
could just pass a 0 right away. Furthermore, it prevents you from using
'out' arguments.

Actually, pointers are needed to write directly to the address they points
to. Using reference to the bogus null-object, which we leave unmodifed
when assign a new value to the reference to return. This makes passing the
bogus value by reference a bit nonsenes. Pointers reach the same effect
without creating any bogus objects, which as stated above has additional
usage advantages.

Peahaps, too much words for the issue. Yet, I do not know any places where
it is discussed.

Personally I find these types of discussions to have null value.

PS
 
V

valentin tihomirov

Frankly, I don't see how it's all that different at all. There are some
minor semantic differences, but for all intents and purposes a "null" in
C# is pretty much the same as a "null" in C++.

Despite you cannot pass the null as argument, which is ubequitous, the most
frequent parameter in C.


Again, how is this difference from passing by reference in C++?

Where do I tell that C# references are different from C++ references? I was
speaking about the difference between "pointers" and "references"!

Using reference to the bogus null-object, which we leave unmodifed when
assign a new value to the reference to return.

I don't understand this statement. How can you leave something unmodified
while at the same time assigning a new value?

Very easily.
function (ref a) {
if (a != null)
a = new object();
}

b = null;
function(ref b);

The null passed by reference is left unmodified ;-) The same effect would be
reached by different 'nulls'
NULL = new Object();
func(ref r) {
if (r != NULL)
r = returnVal;
}

However, I fail to see how this is really much of an advantage. In C# you
would be required to create a dummy local that you would just ignore. In
C++ you have to have code in the function itself to check whether the
parameter is null. Either way, there's extra code, and in the C# case it
eliminates the chance of a null-dereference run-time error (in C++, if you
forget to check for the parameter being null, you can crash).

... and the water is wet. But I did not address this issue! Read it once
again:
It has
two disadvantages though: 1) you must declare a bogus reference
variable;
and 2) initialize it before passing to the function, where you could
just
pass a 0 right away. Furthermore, it prevents you from using 'out'
arguments.[end quote]

Who argues that we should assign null (optional) arguments if the null
passed means "user does not want us to out anything"?

I don't really think you understand the issues you're talking about
anyway

Because you read and respond on the thing I do not address.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
A reference to the special NULL object is not the same thing as the
zero-pointer, which refers nothing (zero address is invalid). That is why I
point out that pointer argument itself is allowed to be zero while reference
is not. A reference must always refer something (whether a valid object or
'null' object).

Only according to your terminology. In C#, a reference can refer to a
real object or it can be null. There is no such thing as a "null
object".
Thanks for the hint. I suppose it is the supposed way to do it in C#. It has
two disadvantages though: 1) you must declare a bogus reference variable;
and 2) initialize it before passing to the function, where you could just
pass a 0 right away. Furthermore, it prevents you from using 'out'
arguments.

Yes, both "out" and "ref" require you to use an actual variable. This
is entirely reasonable given the purpose of ref, IMO.
Actually, pointers are needed to write directly to the address they points
to. Using reference to the bogus null-object, which we leave unmodifed when
assign a new value to the reference to return. This makes passing the bogus
value by reference a bit nonsenes. Pointers reach the same effect without
creating any bogus objects, which as stated above has additional usage
advantages.

No objects are created in the code at the top of this post.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
Despite you cannot pass the null as argument, which is ubequitous, the most
frequent parameter in C.

It's already been pointed out that you *can* use null as an argument.
Where do I tell that C# references are different from C++ references? I was
speaking about the difference between "pointers" and "references"!

You need to understand the difference between *a* reference (which is
like a C++ pointer) and passing something *by* reference which is like
passing by reference in C++.

<snip>
 
A

Austin Ehlers

Despite you cannot pass the null as argument, which is ubequitous, the most
frequent parameter in C.

Quit trying to program in C with C# syntax. Rarely is there a need to
pass a reference type by-ref in C#. In fact, in the past 5 years of
working with C#/.NET, I can't recall ever doing a ref-by-ref method.
The only times I've even used a by-ref was with a struct, either in an
area where I needed maximum performance (and testing revealed a
bottleneck), or for P/Invoke.

Almost always, whenever I see a reference type passed by-ref, I think
WTF are they doing here, and the code is usually wrong.

Please, show me where a ref-by-ref is needed in C#/.NET

Austin

<snip>
 
B

Ben Voigt [C++ MVP]

valentin tihomirov said:
A reference to the special NULL object is not the same thing as the
zero-pointer, which refers nothing (zero address is invalid). That is why
I

There is no special NULL object, and a null pointer has the integral value
zero (try new IntPtr(null).ToInt32()).
 
B

Ben Voigt [C++ MVP]

You can't use a null for a reference parameter in C++ either. The
following generates a compile error, just as the "ref" parameter example
you gave for C# does:

Yes you can. You do have to pass the correct type, however.

void Func(int &i)
{
}

void Caller()
{
Func(*(int*)nullptr);
}

It's a very bad idea, true, but people who use references instead of
pointers simply because "I would have to check for NULL pointers, and
references can't be NULL" are simply misinformed.
 
B

Ben Voigt [C++ MVP]

Austin Ehlers said:
Quit trying to program in C with C# syntax. Rarely is there a need to
pass a reference type by-ref in C#. In fact, in the past 5 years of
working with C#/.NET, I can't recall ever doing a ref-by-ref method.
The only times I've even used a by-ref was with a struct, either in an
area where I needed maximum performance (and testing revealed a
bottleneck), or for P/Invoke.

Almost always, whenever I see a reference type passed by-ref, I think
WTF are they doing here, and the code is usually wrong.

Please, show me where a ref-by-ref is needed in C#/.NET

Immutable reference types, like string. Copy-on-write. Various times you
need ReferenceEquals, not simply a clone, but the return value is already
used.
 
J

Jon Skeet [C# MVP]

Ben Voigt said:
Immutable reference types, like string. Copy-on-write. Various times you
need ReferenceEquals, not simply a clone, but the return value is already
used.

While I can think of some reasons why pass-by-ref of reference types is
sometimes useful, I can't make head or tail of your reply,
unfortunately. However, I suspect I could learn something if you'd be
willing to elaborate.
 
A

Andy Bates

Haven't read the whole thread but in C++... a pointer is used when the
object may/can not exist; otherwise a reference is used when the object must
exist.

You can force a NULL reference to be used in C++ but it's definately not a
practice that I'd recommend.

If you are using a pointer then the check for NULL is imperative where as a
reference must be bound to an object.

- Andy
 
B

Ben Voigt [C++ MVP]

Jon Skeet said:
While I can think of some reasons why pass-by-ref of reference types is
sometimes useful, I can't make head or tail of your reply,
unfortunately. However, I suspect I could learn something if you'd be
willing to elaborate.

The argument against pass ref class by-ref seems to be that you should
modify the referenced class in place. That isn't possible for immutable
types, like string. To return string data by reference, you can pass a
string variable by-ref, (or use a StringBuilder).

Copy-on-write: If you aren't allowed to modify the object in-place, but have
to clone it in order to change it, then the caller's reference needs to be
updated to the new copy. Again, ref-by-ref. strings are actually a subset
of this case.

If the resulting value has to compare equal by referential equality every
time it is returned, then you need to set the caller's reference equal to
your own. Again, ref-by-ref.
 
B

Ben Voigt [C++ MVP]

Andy Bates said:
Haven't read the whole thread but in C++... a pointer is used when the
object may/can not exist; otherwise a reference is used when the object
must exist.

Again, a reference can be just as invalid as a pointer.
You can force a NULL reference to be used in C++ but it's definately not a
practice that I'd recommend.

If you are using a pointer then the check for NULL is imperative where as
a reference must be bound to an object.

No, it isn't. You can make the contract such that "such and such argument
must not be NULL", then you don't need to check it. And no, a reference
doesn't need to be bound to an object. *p creates a reference for any
pointer p. If the pointer was NULL, there is no object.

Admittedly my example was contrived, that was to use as much of the previous
poster's incorrect claim as possible.
 
P

Peter Duniho

It's a very bad idea, true, but people who use references instead of
pointers simply because "I would have to check for NULL pointers, and
references can't be NULL" are simply misinformed.

It's true. In C++ you can use casting to get around practically any
limitation intentionally put into the language.

I don't see how that invalidates my point though. I have never written
C++ code that checks something passed by reference for null references,
nor have I ever had to maintain code written that way.

I never suggested that the reason to use references was to avoid having to
check for null pointers, but I do feel that is in fact an advantage (if
the caller wants to explicitly get around that safe-guard, that's a bug in
the caller akin to using Reflection in C# to get around a variety of
safe-guards C# puts into place), and I bristle at your implication (if not
outright accusation) that I am "misinformed" just for thinking so.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top