'null' references

P

Peter Duniho

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

You _can_ pass null as an argument. You just can't pass null as an
argument for a "ref" parameter.

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

Since a "ref" parameter is essentially the same as C++'s "&" by-reference
parameter, and since the "ref" parameter type (along with "out" which isa
special case of "ref") is the only situation in which your complaint about
not being able to pass null is true, _that_ is "where you tell that C#
references are different from C++ references".

You brought it up. I'm just pointing out the fallacy in your complaint.
Very easily.
function (ref a) {
if (a != null)
a = new object();
}

b = null;
function(ref b);

The above code does _not_ leave "b" unmodified when an new value is
assigned. It does leave "b" unmodified in the example calling code, but
that's only because the function also does not assign a new value.
The null passed by reference is left unmodified ;-)

The null passed by reference would be left unmodified in any case. It's
only "b" that would be modified or not, as that's the variable passed by
reference.
The same effect would be
reached by different 'nulls'
NULL = new Object();
func(ref r) {
if (r != NULL)
r = returnVal;
}

I have no idea what you expect that code to do. You can't assign an
object reference ("new Object()") to "null". You haven't declared "NULL",
so I don't know if you mean that to be the same as "null", or something
entirely different.
.. and the water is wet. But I did not address this issue!

Which issue? I agree that you didn't specifically raise the question of
checking for null values. However, that _is_ really the only practical
difference between your apparent desire to pass something by a pointer to
the variable versus the C# "ref" parameter type.

In that respect, you certainly did by implication "address this issue".
Read it once
again:
It has
two disadvantages though: 1) you must declare a bogus reference
variable;

So too you must in C++, if using "by-reference" parameter passing.
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]

What prevents you from using "out" arguments? The use of the "out"
parameter type is in fact how you can avoid having to initialize the
variable passed into the function.
Who argues that we should assign null (optional) arguments if the null
passed means "user does not want us to out anything"?

What do you mean by "assign null arguments"? You can't assign anything to
a null reference or pointer.
Because you read and respond on the thing I do not address.

The fact that you think my response isn't relevant to the thing you are
talking about is in fact the very evidence that you don't understand the
thing that you are talking about.

Pete
 
L

Larry Smith

The fact that you think my response isn't relevant to the thing you are
talking about is in fact the very evidence that you don't understand the
thing that you are talking about.

I haven't read the entire thread but the issue to me boils down to this. Why
isn't the following allowed:

void Func(out Whatever whatever)
{
if (whatever != null)
{
whatever = new Whatever();
}
}

Func(null);
 
L

Larry Smith

You can't use a null for a reference parameter in C++ either. The
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.

Not only is it bad, it's undefined behaviour so it doesn't qualify as valid
C++. You can't legally dereference a null pointer nor is a null reference
legally possible.
 
A

Austin Ehlers

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).

Why not just use the return value, like String does? If you have
multiple parameters that need to be changed, then it is usually bad
code, trying to do too much in one method, and should be refactored
into a better design.

Seeing a reference type passed by-ref in code, particularly from
someone new to C#/.NET, is like seeing a class with a finalizer: it's
occasionally right, but not often.

(I'm also ignoring things like Remoting, as that's outside normal
C#/.NET usage.)
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.
Same.

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.

Sorry, I'm not following you here. Any example code?

Austin
 
P

Peter Duniho

Why not just use the return value, like String does? If you have
multiple parameters that need to be changed, then it is usually bad
code, trying to do too much in one method, and should be refactored
into a better design.

I agree that for immutable types, the best solution is usually to return a
new instance as the result from a method, rather than using a "ref"
parameter. However, consider situations like TryParse where you want to
return more than one value: the new instance and a result code of some
sort, for example. Are you suggesting that the TryParse pattern is
indicative of poor design?

It's true that these situations aren't very common. But I wouldn't go so
far as to say that one never needs to pass reference variables by
reference.
Seeing a reference type passed by-ref in code, particularly from
someone new to C#/.NET, is like seeing a class with a finalizer: it's
occasionally right, but not often.

"Occasionally right" being the operative phrase, IMHO. You wrote "Please,
show me where a ref-by-ref is needed in C#/.NET". I interpreted Ben's
reply simply as doing just that, showing you where it's needed.

Pete
 
P

Peter Duniho

I haven't read the entire thread but the issue to me boils down to
this. Why
isn't the following allowed:

void Func(out Whatever whatever)
{
if (whatever != null)
{
whatever = new Whatever();
}
}

Func(null);

I think it does boil down to that, and I think the answer is the same as
the reason why you can't do this in C++:

void Func(Whatever &whatever)
{
if (whatever != null)
{
whatever = new Whatever();
}
}

Func(nullptr);

In other words, there's no practical different in this respect between
C++ and C#, in spite of what the OP claims.
 
L

Larry Smith

In other words, there's no practical different in this respect between
C++ and C#, in spite of what the OP claims.

Apparently so but it didn't have to be that way. It may be a religious issue
but I would have voted to support it.
 
A

Austin Ehlers

I agree that for immutable types, the best solution is usually to return a
new instance as the result from a method, rather than using a "ref"
parameter. However, consider situations like TryParse where you want to
return more than one value: the new instance and a result code of some
sort, for example. Are you suggesting that the TryParse pattern is
indicative of poor design?

It's true that these situations aren't very common. But I wouldn't go so
far as to say that one never needs to pass reference variables by
reference.

But is that a reference type? Besides IPAddress.TryParse, they're all
structs. (Notice I said "usually bad, trying to do too much in one
method". Parsing a string into a type is a common, single idea).
"Occasionally right" being the operative phrase, IMHO. You wrote "Please,
show me where a ref-by-ref is needed in C#/.NET". I interpreted Ben's
reply simply as doing just that, showing you where it's needed.

And that's fine. I'm just trying to show the OP that things are
different in C# than C/C++, and trying to use C-style code will lead
to a bad design.

Austin
 
J

Jon Skeet [C# MVP]

Ben Voigt said:
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).
Agreed.

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.

Right, I 'm with you.
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.

Hmm... that may be an idiom I've never come across. The first two make
absolute sense (even if they're fairly rarely required), but this one
is outside my experience.
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
You _can_ pass null as an argument. You just can't pass null as an
argument for a "ref" parameter.

And it's important to note that it's not to do with it being null -
it's to do with being a *value* rather than a *variable*. If you try to
use the result of a method call as a ref parameter you fail in the same
way - ditto if you use a string literal.

<snip>
 
J

Jon Skeet [C# MVP]

Larry Smith said:
I haven't read the entire thread but the issue to me boils down to this. Why
isn't the following allowed:

void Func(out Whatever whatever)
{
if (whatever != null)
{
whatever = new Whatever();
}
}

Func(null);

For two reasons:

1) out/ref arguments must be *variables* not values
2) The value of an out parameter isn't definitely assigned at the start
of a method, so you can't compare it with null.
 
V

valentin tihomirov

It's already been pointed out that you *can* use null as an argument.

Neither func(null), nor func(ref null) works. I have checked myself.

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++.

C++ references are also "like" C++ pointers. But not the same. They are
different. Nulls are not allowed where reference is required. That is the
difference.
 
V

valentin tihomirov

Since a "ref" parameter is essentially the same as C++'s "&" by-reference

THEY ARE NOT !!!

Look at the google newsgruop I reference


parameter, and since the "ref" parameter type (along with "out" which is a
special case of "ref") is the only situation in which your complaint about
not being able to pass null is true, _that_ is "where you tell that C#
references are different from C++ references".

Show me where I tell that Delphi/C++ references are different from C#
references? I repeat once again, THESE ARE POINTERS WHICH ARE DIFFERENT FROM
REFERENCES !!!





The same effect would be
reached by different 'nulls'
NULL = new Object();
func(ref r) {
if (r != NULL)
r = returnVal;
}
I have no idea what you expect that code to do. You can't assign an
object reference ("new Object()") to "null". You haven't declared "NULL",
so I don't know if you mean that to be the same as "null", or something
entirely different.

NULL is a marker. I could name it INVALID_HANDLE or somethig. The usage is
the same as you do with 'null' marker. You use the marker to inform the
function that you do not want to obtain a result via the 'ref' param. That
is the different with pointer argument. With the pointer you have an option:
whether to pass a reference or not to pass. With the ref argument you have
no option -- the reference must be passed. You addign it a bogus marker. But
the function is still capable to return a value via the reference. The
program will not crush. It will if null pointer is used.

Importing a dll function, one may declare their arguments wheter as poitners
of references. Both will work, because internal mechanics, the
implementation is the same. But reference prevents passing 'null'. The
compiler will not allow. They must refer existing object.

Is it so hard to understand? Why Delphi noobs understad this difference
between declarations from the start? Should be my bad explanation.



Which issue? I agree that you didn't specifically raise the question of
checking for null values. However, that _is_ really the only practical
difference between your apparent desire to pass something by a pointer to
the variable versus the C# "ref" parameter type.
In that respect, you certainly did by implication "address this issue".

I did not ask anybody to warn me about the dangers of using null pointers.



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]
What prevents you from using "out" arguments? The use of the "out"
parameter type is in fact how you can avoid having to initialize the
variable passed into the function.

You suggest that I pass a bogus ref var initialized to 'null' and you do not
understand that this prevents me from specifying the function param as
'out'? Have you tried to read the 'out' parameters in the funtion?


What do you mean by "assign null arguments"? You can't assign anything to
a null reference or pointer.

I mean that if user sepcifies 'null' in the pointer argument, (s)he does not
refer anything. This means, (s)he does not pass any data in neither wants
any data out. And I do not argue that we should read/write address 0
crashing the app.



Because you read and respond on the thing I do not address.
The fact that you think my response isn't relevant to the thing you are
talking about is in fact the very evidence that you don't understand the
thing that you are talking about.

Evidence? Can you show me the prove? So far, I will go on thinking that your
answers are not relevant because thet are not relevant.
 
V

valentin tihomirov

Larry grasped it very well. But the correct answer, which I assumed in the
OP, is not because C# references are the same as references in other
languages. Doing so is not allowed because the pointers, which are allowed
to refer any areas of memory where no valid objects exist including address
0, are not supported in C#.
 
V

valentin tihomirov

You _can_ pass null as an argument. You just can't pass null as an
And it's important to note that it's not to do with it being null -
it's to do with being a *value* rather than a *variable*. If you try to
use the result of a method call as a ref parameter you fail in the same
way - ditto if you use a string literal.

To be relevant to the raised issue, it is important to note that the topic
is about passing arguemtns by pointers/references and that the 'null' is a
'literal'. That is why I state that 'null' is not allowed to pass as
argument.
 
V

valentin tihomirov

Yes, both "out" and "ref" require you to use an actual variable. This
is entirely reasonable given the purpose of ref, IMO.

But you cannot read the 'out' parameter in order to accoumplish the trick of
passing 'null' reference.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

John said:
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).

I don't really see that as a problem. If a method has ref/out parameter
that you are not interrested in, the method is not intended for what you
are interrested in either. If you are using a method for something other
than it was intended for, you still have to supply the parameters for
what it was intended for.

Besides, ref/out parameters are rarely used in oop anyway. :)
Other issues include a lack of "const-correctness", no
covariant return types (a must in OOP),

Hardly a must, but it would be nice.
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),

I think that is a good thing. It makes you write code that corresponds
to the business rules, instead of writing code that relies on the
business rules never changing. If the rules change (and some surely
will), the compiler can catch any code that you failed to change,
instead of merrily create code that uses undefined values.

If you really think that it's a problem, you can use VB instead, which
does initialise the variables automatically. This of course introduces
some other potential problems, 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.

I surely agree that the early release does cause some baggage in the
framework. If it was a correct decision or not businesswise, that's hard
to tell, but I am sure that they were aware of the consequences when
they made the decision. A business makes business decisons.
 
L

Larry Smith

Larry Smith said:
For two reasons:

1) out/ref arguments must be *variables* not values
2) The value of an out parameter isn't definitely assigned at the start
of a method, so you can't compare it with null.

You're explaining the language's existing rules which is fine, but I'm
questioning why it was done that way in the first place. Let's say I have a
function like "_splitpath" in the CRT. It takes a full path name as arg1 and
returns its drive letter, directory, file name and extension in the next
four "out" parameters. I'm only interested in the directory for instance so
I want to pass "null" for the other "out" arguments. I can't do this however
which is very inconvenient. I'm forced to pass all "out" arguments IOW.
Someone might argue not to design methods like this but there's nothing
inherently wrong with it so it's ultimately the programmer's choice. It may
also prove more efficient in some cases, letting the function know it
doesn't have to carry out the extra work of retrieving all "out" parameters.
Nor do I have to create additional methods to retrieve each individual piece
of info or otherwise create an extra class to store all this data. Sometimes
I'm even just intersested in a function's return value without caring about
the "out" parameter(s). Barring any tangible constraints on the language's
ability to implement this feature, I see no valid reason why the rules can't
and don't support it.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
Neither func(null), nor func(ref null) works. I have checked myself.

To what signature? Here's an example of func(null) working fine:

using System;

class Test
{
static void Main()
{
func(null);
}

static void func(object o)
{
}
}

As you haven't provided the signature of "func" it's hard to know
exactly what you're doing wrong. If func is declared with two
parameters, or a value type parameter, or a ref/out parameter then it
will certainly fail, but that's a different matter.
C++ references are also "like" C++ pointers. But not the same. They are
different. Nulls are not allowed where reference is required. That is the
difference.

The reason you can't do "ref null" is nothing to do with the value null
itself though - it's because you're trying to use a value rather than a
variable.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
To be relevant to the raised issue, it is important to note that the topic
is about passing arguemtns by pointers/references and that the 'null' is a
'literal'. That is why I state that 'null' is not allowed to pass as
argument.

Except it is - just not as an argument for a ref parameter.
 

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