'null' references

B

Barry Kelly

Larry said:
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.

Of course, this is a red herring as far as C# and .NET are concerned.
Implementing this such that it causes a null reference exception (just
like a null object reference) wouldn't be a problem.

It would be a surprising thing to add, so I'm quite sure it won't ever
be added, but all the same, I think this is a red herring.

-- Barry
 
J

Jon Skeet [C# MVP]

Barry Kelly said:
What if the values you're retrieving have different costs, and you don't
want to pay the whole cost, only the cost for the bits you want?

Then as I said before, you could specify another parameter which said
exactly what you wanted to retrieve.
There are plenty of alternative designs, but I don't think any of them
match the C/C++ solution in clarity or conciseness.

It certainly wouldn't be as concise as the C++ solution, but I'd say it
would be clearer. Currently each parameter would be doing two things:
specifying an option *and* providing somewhere to store a result. I
think it's clearer to separate those. It's a personal opinion though -
I don't think there's a right or wrong answer on that front.
Some off the top of my head:
* have many methods instead of one (API bloat)

But potentially increased clarity. Having fewer methods certainly isn't
always a good thing.
* have an auxiliary flags argument that specifies the arguments you're
interested in
* return a proxy object which calculates and caches the values on demand
(implementation overhead, runtime overhead, API bloat)
Indeed.


That's a syntax issue - it's pretty irrelevant.

No, it's not - not unless you think that a language should be all
things to all people. Making the language more complex is a cost in my
view, and it needs to be balanced against the benefit.
 
V

valentin tihomirov

valentin tihomirov said:
THEY ARE NOT !!!

Look at the google newsgruop I reference

Ups, the point was to remid that C++ pointers are different from references.
 
B

Ben Voigt [C++ MVP]

valentin tihomirov said:
Ups, the point was to remid that C++ pointers are different from
references.

But they *aren't* different, except in a syntactic sugary kind of way.
Maybe if you consider the fact that a reference can't be redirected... but
that's the same as a const pointer (as opposed to a pointer to const data).
 
V

valentin tihomirov

If they are not different, they are the same as C# refs and I can pass
'null's.
 
V

valentin tihomirov

It certainly wouldn't be as concise as the C++ solution, but I'd say it
would be clearer. Currently each parameter would be doing two things:
specifying an option *and* providing somewhere to store a result. I
think it's clearer to separate those. It's a personal opinion though -
I don't think there's a right or wrong answer on that front.

Formerly, when we business did not feed us with disposable packages, we
used to buy liquid products in our tare. So, you come to dairyman, put your
package in front of him to say you do not need any milk. It is more
rational, IMO, not to provoke the party by not submitting the the package to
him (and not taking it with you to shop, in addition). The daryman should
still check if the can is provided before filling it.

You legitimate the girls who seduce men and then say "no" when the party
starts reacting. The optimization rule tells us: do not invoke resources if
you will not need them. With the extra flag, you still have to allocate the
container:

object container;
func(false, out container);
 
J

Jon Skeet [C# MVP]

You legitimate the girls who seduce men and then say "no" when the party
starts reacting. The optimization rule tells us: do not invoke resources if
you will not need them. With the extra flag, you still have to allocate the
container:

object container;
func(false, out container);

Well, that's not creating any objects. It's allocating space for the
variable, but that's all.

That's rarely the sort of API I'd write using C#, however - I'd almost
always use a return variable instead. TryParse etc use out parameters,
but I rarely use out parameters beyond that situation.

Jon
 
L

Larry Smith

Yes you can. You do have to pass the correct type, however.
Is creating a reference from a pointer defined as dereferencing that
pointer, even though no access through that pointer occurs until much
later?

I don't understand your point. What I replied to was your "yes you can"
response to someone's comment that "you can't use a null for a reference
parameter in C++.". No you can't. Dereferencing a null pointer is stricly
undefined behaviour so the language's rules have nothing to say about it
(except to make it perfectly clear that is undefined). Moreover, a "null
reference" is impossible in a language where null references don't exist
according to the rules. Surely you know this so your statement is not
correct nor is any contrived example that's based on undefined behaviour.
 
V

valentin tihomirov

That's rarely the sort of API I'd write using C#, however - I'd almost
always use a return variable instead. TryParse etc use out parameters,
but I rarely use out parameters beyond that situation.

I do not undesrstand what are you trying so say. Should we vote the
features, which are rarely needed, out of the language(s)?
 
B

Ben Voigt [C++ MVP]

valentin tihomirov said:
If they are not different, they are the same as C# refs and I can pass
'null's.

C++ pointers, C++ references, and C# pointers all have the same semantics.
They can refer to an instance, NULL, or some invalid location in memory.

C# calls to ref and out arguments are different (although you will find that
C++/CLI can pass a NULL-ed reference to such a C# function without
difficulty).
 
B

Ben Voigt [C++ MVP]

Larry Smith said:
I don't understand your point. What I replied to was your "yes you can"
response to someone's comment that "you can't use a null for a reference
parameter in C++.". No you can't. Dereferencing a null pointer is stricly
undefined behaviour so the language's rules have nothing to say about it
(except to make it perfectly clear that is undefined). Moreover, a "null
reference" is impossible in a language where null references don't exist
according to the rules. Surely you know this so your statement is not
correct nor is any contrived example that's based on undefined behaviour.

What I'm saying is that for code like:

void fn(int* p)
{
WaitForSingleObject(semaphore);
*p++;
ReleaseSemaphore(semaphore);
}

Clearly the above is not exception safe, and if p is NULL or otherwise
invalid to cause an access violation, you will leak semaphore counts. To
say that null and invalid references don't exist suggests that if you would
just change (int* p) to (int& i) the function would be unable to fail and
therefore correctly manages the semaphore, but this is a bogus argument.
The reference version of the function can still throw an access violation
and still needs to be coded for exception safety. This is what I mean when
I say that people who use references to avoid the problems associated with
invalid pointers are misinformed.
 
L

Larry Smith

What I'm saying is that for code like:
void fn(int* p)
{
WaitForSingleObject(semaphore);
*p++;
ReleaseSemaphore(semaphore);
}

Clearly the above is not exception safe, and if p is NULL or otherwise
invalid to cause an access violation, you will leak semaphore counts. To
say that null and invalid references don't exist suggests that if you
would just change (int* p) to (int& i) the function would be unable to
fail and therefore correctly manages the semaphore, but this is a bogus
argument. The reference version of the function can still throw an access
violation and still needs to be coded for exception safety. This is what
I mean when I say that people who use references to avoid the problems
associated with invalid pointers are misinformed.

According to the standard (8.3.2[4])

"... a null reference cannot exist in a well-defined program, because the
only way to create such a reference would be to bind it to the "object"
obtained by dereferencing a null pointer which causes undefined behaviour".

I understand your point but your own argument is what's "bogus". As soon as
you engage in undefined behaviour then all bets are off. If you define the
above function as taking a reference arg then the undefined behaviour occurs
the moment someone tries to dereference an invalid pointer. That has nothing
to do any function you may be calling at the time. The undefined behaviour
occurs before the function has even started so how can it protect itself.
There is no valid way. Everything might blow up before the function even
begins but the entire environment should be considered corrupt even if it
does start. Your attempt to "protect" the function would therefore be
unreliable but that's beside the point. An "invalid reference" doesn't exist
which is the point. Null pointers do however. So do invalid pointers which
are legal so long as you don't dereference them. The pointer version of the
function would therefore have to protect itself while the reference version
has nothing to protect itself against (since invalid references don't
exist). Even for the pointer version however, it can't protect itself
against an invalid (non-null) pointer using any standard technique noting
that an "access violation" isn't even guaranteed. Nothing is guaranteed and
standard C++ can't even catch these types of so-called "exceptions". A
reference parameter is therefore inherently safe unlike a pointer parameter
since null references don't exist so a reference parameter can never refer
to an invalid object by definition. Pointers legally can however so
dereferning an invalid pointer isn't safe (which is your point) but that has
nothing to do with passing the dereferenced value as a reference arg. I
therefore suggest that you're the one who's misinformed.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
I do not undesrstand what are you trying so say. Should we vote the
features, which are rarely needed, out of the language(s)?

We should consider the cost in complexity of adding features to a
language against the benefit they provides. That's how you stop a
language from trying to be all things to all people - which always
fails.
 
B

Ben Voigt [C++ MVP]

Larry Smith said:
What I'm saying is that for code like:

void fn(int* p)
{
WaitForSingleObject(semaphore);
*p++;
ReleaseSemaphore(semaphore);
}

Clearly the above is not exception safe, and if p is NULL or otherwise
invalid to cause an access violation, you will leak semaphore counts. To
say that null and invalid references don't exist suggests that if you
would just change (int* p) to (int& i) the function would be unable to
fail and therefore correctly manages the semaphore, but this is a bogus
argument. The reference version of the function can still throw an access
violation and still needs to be coded for exception safety. This is what
I mean when I say that people who use references to avoid the problems
associated with invalid pointers are misinformed.

According to the standard (8.3.2[4])

"... a null reference cannot exist in a well-defined program, because the
only way to create such a reference would be to bind it to the "object"
obtained by dereferencing a null pointer which causes undefined
behaviour".

I understand your point but your own argument is what's "bogus". As soon
as you engage in undefined behaviour then all bets are off. If you define
the above function as taking a reference arg then the undefined behaviour
occurs the moment someone tries to dereference an invalid pointer. That
has nothing to do any function you may be calling at the time. The
undefined behaviour occurs before the function has even started so how can
it protect itself. There is no valid way. Everything might blow up before
the function even begins but the entire environment should be considered
corrupt even if it does start. Your attempt to "protect" the function
would therefore be unreliable but that's beside the point. An "invalid
reference" doesn't exist which is the point. Null pointers do however. So
do invalid pointers which are legal so long as you don't dereference them.
The pointer version of the function would therefore have to protect itself
while the reference version has nothing to protect itself against (since
invalid references don't exist). Even for the pointer version however, it
can't protect itself against an invalid (non-null) pointer using any
standard technique noting that an "access violation" isn't even
guaranteed. Nothing is guaranteed and standard C++ can't even catch these
types of so-called "exceptions". A reference parameter is therefore
inherently safe unlike a pointer parameter since null references don't
exist so a reference parameter can never refer to an invalid object by
definition. Pointers legally can however so dereferning an invalid pointer
isn't safe (which is your point) but that has nothing to do with passing
the dereferenced value as a reference arg. I therefore suggest that you're
the one who's misinformed.

I agree with everything you say about the standard. What I'm referring to
as uninformed, is stuff like the following (quoted from the C++ group this
week):

<blockquote>
With references we don't need to check that 'pMyPtrArgument != NULL',
so with references the code tends to be more elegant and robust, IMHO.
</blockquote>

This is absurd. With pointers, the behavior is well-defined. If someone
passes you a wild pointer, you may trample their memory or cause an access
violation, but exception-safety (combined with a check that you aren't
trashing your own stack frame) will allow your library to keep its internal
resources in a valid state. With references, you get "undefined behavior"
according to the standard, or the same behavior as pointers in practically
every implementation. That's hardly "more robust", agreed?
 
C

Christof Nordiek

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

b = null;
function(ref b);
I don't understand the meaning of this pseudocode. What would/could be the
type of a and b?

You're not passing a null reference or null pointer here, but a variable
that contains null. Many would say it's passing a null (reference) by
reference. I understand it better as passing a varaible (not a reference).

What you seem to want, is a ref parameter where you can pass a variable
aswell as no variable. Right?
That is not possible in C#, atleast not with ref parameter. Could be
emaulated in unsafe code with pointers.

Christof
 
C

Christof Nordiek

valentin tihomirov said:
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#.

references in the context of reference types actually can point to address
zero, wich is what a null reference is.
ref variables can't point to zero nor can they point to object instances,
they can only point to variables

You should not that reference variables vs. value variables in C# is totally
different from reference types vs value types.

Christof
 
C

Christof Nordiek

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);
The question is: what does whatever != null mean.
It tests if the content of the variable given by the caller is empty (has
content null).
It seems you want to test if the variable itself is zero, meaning no
variable given by the caller.

The would be a very problematic thing in a managed language like C#. The
compiler would have to check on any access to the parameter, if the
parameter really is assigned to a variable (of the correct type) or not,
maybe adding a lot of runtime checks. In C this is in the responsability of
the programmer and easily leads to very unmaintainable bugs.
Additionally C# would have to have additional syntax for checking if a
reference parameter is pointing to a variable or not. Your given syntax is
already occupied.

Christof
 

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