params (rant)

P

PIEBALD

Given a method like

void F ( params object[] args ) { ... }

I had always _assumed_ that args would never be null, but now it's been
brought to my attention that if the caller uses

F ( null )

then args _will_ be null because the compiler can implicitly convert the
null to an object[].

But I doubt that this is the desired behaviour in most cases, certainly _I_
expect (and prefer) args to be an array containing one null, just as

F ( null , null )

results in an array containing two nulls.

Some experimentation has shown that

F ( new object[] { null } )
and
F ( (object) null )

result in the desired array, but the caller shouldn't have to go through
such hoops.

It seems to me that rather than have the compiler see if the value can be
implicitly converted to the array type, it shoud determine if the value _is_
the array type.


I realize that it's too late to change the language, and if someone _does_
want the parameter to be null, then the current behaviour seems the only way.
But, man, now I have to go through my code looking for methods that take
params and protect against null.
 
J

Jon Skeet [C# MVP]

PIEBALD said:
Given a method like

void F ( params object[] args ) { ... }

I had always _assumed_ that args would never be null, but now it's been
brought to my attention that if the caller uses

F ( null )

then args _will_ be null because the compiler can implicitly convert the
null to an object[].

Indeed. params *allows* the caller to use the F(x, y, z) syntax, but it
doesn't *force* it.
But I doubt that this is the desired behaviour in most cases, certainly _I_
expect (and prefer) args to be an array containing one null, just as

F ( null , null )

results in an array containing two nulls.

Note that this will only be the behaviour when you're using the
*literal* null. If you do:

object o = null;
F(o);

or something similar, that will be handled as you expect. I think it's
relatively rare to need to call a method with params parameter passing
a null literal - and given that you might *also* want to call it
passing a null argument instead of an array containing a null value,
the language has to make a trade-off anyway.
It seems to me that rather than have the compiler see if the value can be
implicitly converted to the array type, it shoud determine if the value _is_
the array type.

I disagree. I think it's fine the way it is.
I realize that it's too late to change the language, and if someone _does_
want the parameter to be null, then the current behaviour seems the only way.
But, man, now I have to go through my code looking for methods that take
params and protect against null.

You should have done so anyway - or at least expected that the value
could be null. After all, you could have:

object[] x = null;
F(x);

Are you surprised that the above compiles? If not, what would you have
expected it to do?
 
J

Jon Skeet [C# MVP]

On Sep 29, 12:04 am, "Peter Duniho" <[email protected]>
wrote:

With that perspective, I think one could expect your example to compile to > a single-element parameter list with the value of "null" as that element.  
In other words, the parameter array would still not be null; it would  
_contain_ a null.

Good point. Here's a clearer example, without the ambiguity stemming
from the fact that object[] can be converted to object:

void Foo(params string[] args)
{
}
....
string[] x = null;
Foo(x);

Clearly that can't be treating x as a string, because it's a string[].
Therefore if the above compiles, it's possible for a "params"
parameter to be null. Therefore one should check "params" parameters
for nullity in the same way as other parameters.

The only argument against that would be if the OP wouldn't have
expected the above code to compile - which would be a horrible
restriction, IMO.

Jon
 
M

Marc Gravell

And once again I find myself yearning for the missing "argument cannot
be null" language feature. Maybe one day...

Marc
 
P

Pavel Minaev

You should have done so anyway - or at least expected that the value
could be null. After all, you could have:

object[] x = null;
F(x);

Are you surprised that the above compiles? If not, what would you have
expected it to do?

I think the problem here is that when checking for null params, one
could reasonably think that just throwing ArgumentNullException would
be fine (because it handles the case above). But then it can puzzle
the client, who can do:

F(null);

and get an ArgumentNullException on that, but not on:

F(null, null);

which is certainly rather confusing.
 
J

Jon Skeet [C# MVP]

On Sep 29, 7:35 am, "Peter Duniho" <[email protected]>
wrote:

"Horrible"?  I don't know.  I mean, I do appreciate the C# implementation  
of variable-length parameter lists.  But other languages get by just  
fine.  If anything, because of the way C# does it, in reality it reallyis  
just glossy syntax on top of a very basic idea: passing an array.

Had C# prohibited the example you offer here, I don't think it'd be that  
big of a deal.  You just couldn't use variable-length parameter lists in a  
scenario where what you really wanted to pass was a reference to an array,  
possibly null.  You'd have to declare and use it more explicitly.  Nobig  
deal, at least for me it wouldn't be.

I think it would have been a significant limitation. For instance,
consider this exception constructor:

public MyException (string format, params object[] args) :
base(string.Format(format, args))
{
...
}

I use that kind of thing reasonably often - I like to be able to make
it easy for callers to format text without explicitly calling
string.Format themselves. However, the restriction above would prevent
*my* code from calling string.Format. We'd potentially have to have
overloads for everything - string.Format(string, object[]),
string.Format(string, params object[]) which just ends up being silly
IMO. It would also rely on everyone who implemented a method with a
"params" parameter being considerate enough to provide the overload.

Jon
 

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