method ref to arbitrary value type instance

G

Guest

It seems that in C#, given an instance "a" of some value type "A", one can pass a by reference to functions with signatures of either "void f(object obj)" or "void g(ref A obj)". But passing a into a function with signature "void f(ref object obj)" gives a compile error -- why

(This is part of solving the original problem posed here: http://www.csharp-station.com/ShowPost.aspx?PostID=3625 What I need now is a method that accepts a ref to an arbitrary value type instance, or some other approach to the original problem. Ideas would be welcome.

% cat u.c
using System

struct A
public A(int x, int y) { d_x = x; d_y = y;
public override string ToString(
{ return String.Format("({0},{1})", d_x, d_y);
/
int d_x, d_y


class RefTest

static void f(object obj
{ Console.WriteLine("f: obj={0}", obj);

static void g(ref A obj
{ Console.WriteLine("g: obj={0}", obj);

static void h(ref object obj
{ Console.WriteLine("h: obj={0}", obj);

static void i(ref System.ValueType obj
{ Console.WriteLine("i: obj={0}", obj);

static void Main(

A a = new A(3,2)

f(a)

g(ref a)

// h(ref a)
// u.cs(33,5): error CS1502: The best overloaded method match for 'RefTest.h(ref object)' has some invalid argument
// u.cs(33,11): error CS1503: Argument '1': cannot convert from 'ref A' to 'ref object

// i(ref a)
// u.cs(37,5): error CS1502: The best overloaded method match for 'RefTest.i(ref System.ValueType)' has some invalid argument
// u.cs(37,11): error CS1503: Argument '1': cannot convert from 'ref A' to 'ref System.ValueType
 
J

Jon Skeet [C# MVP]

Andrew said:
It seems that in C#, given an instance "a" of some value type "A", one
can pass a by reference to functions with signatures of either "void
f(object obj)" or "void g(ref A obj)". But passing a into a function
with signature "void f(ref object obj)" gives a compile error -- why?

The type for a parameter which is passed by reference has to be exactly
the same as the type of the actual parameter. Leave boxing out of the
picture here, and let's use string as an example. Suppose I have a
string variable x, and a method which takes "ref object obj" as a
formal parameter. You might think it would be okay to pass "ref x" as
the actual parameter... but what if the code for the method being
called was:

void Foo (ref object obj)
{
obj = new object();
}

Suddenly you have a string variable which contains a reference to a
non-string object!

Instead, you need to do:

object tmp = x;
Foo (ref tmp);

and then if you're really confident that tmp will still be a string
afterwards you can do:

x = (string) tmp;

See http://www.pobox.com/~skeet/csharp/parameters.html for more
information about pass-by-reference and pass-by-value semantics.
 
G

Guest

I see

It does seem a bit peculiar though that there is only one way to get a reference to a value instance (by making a method that accepts a ref to a value instance of a specific type), and that way does not allow a way to get a reference to an arbitrary value type instance. Maybe the ability to do that would lead to trouble too.
 
J

Jon Skeet [C# MVP]

Andrew said:
I see.

It does seem a bit peculiar though that there is only one way to get a
reference to a value instance (by making a method that accepts a ref
to a value instance of a specific type), and that way does not allow a
way to get a reference to an arbitrary value type instance. Maybe the
ability to do that would lead to trouble too.

You need to be very clear about the difference between *a* reference
and passing a parameter *by* reference.

If you want to pass an arbitrary value type *by* reference, you could
do:

int x = 5;
ValueType v = x;
Foo (ref v);
x = (int) v;


Foo (ref ValueType v)
{
....
}

Again though - if Foo actually is implemented as something like:

v = 't';

then the cast will fail...
 
J

Jon Skeet [C# MVP]

Andrew said:
Was I not clear about this?

No. For instance:

<quote>
It does seem a bit peculiar though that there is only one way to get a
reference to a value instance (by making a method that accepts a ref to
a value instance of a specific type), and that way does not allow a way
to get a reference to an arbitrary value type instance.
</quote>

"Reference" when used as a noun in .NET is specifically a reference to
null or an object on the heap. Passing a value type parameter by
reference *doesn't* do that - boxing does, effectively. That's the kind
of care over terminology I'm encouraging. I know it sounds horribly
pedantic, but I think it makes discussions much more useful.
 
G

Guest

In that paragraph I was using the term "reference" in the general computer science sense. I hope this clarifies things for you

Andrew
 
J

Jon Skeet [C# MVP]

Andrew said:
In that paragraph I was using the term "reference" in the general
computer science sense. I hope this clarifies things for you.

Yes, I thought you probably were - and while that's all very well, it
confuses things when talking in a .NET forum. I find it's easier to
move a .NET discussion forward when talking in *purely* .NET terms
wherever possible.
 
G

Guest

I can appreciate wanting people to use what you think is standard terminology. Of course, one way to drive people away from a domain is to complain about their use of perfectly reasonable but outside-domain terminology while not answering their question. And it's just not reasonable to expect that people are going to frame their discussion in exactly the terminology you want. What would be better is to point out what you think are imprecisions, when helping along the main discussion

What happens when someone just talks about the terminology, and not the main question, is unfortunate and inevitable. In this thread, and in another thread I started last fall, you ended up sidetracking the discussion to the point where there is virtually no chance of anyone replying to the followup question that I asked. That is not helpful

I mention this in the spirit of trying to get you to think about this next time. The first response you wrote was helpful to me; the other ones have been anti-helpful because they sidetracked the discussion. Now, people get to read us going back and forth about something they could care less about, and possibly they get to read me writing the same question in another thread, if I want an answer.
 
J

Jon Skeet [C# MVP]

Andrew said:
I can appreciate wanting people to use what you think is standard
terminology. Of course, one way to drive people away from a domain is
to complain about their use of perfectly reasonable but outside-domain
terminology while not answering their question. And it's just not
reasonable to expect that people are going to frame their discussion
in exactly the terminology you want. What would be better is to point
out what you think are imprecisions, when helping along the main
discussion.

I was trying to help answer the question at the same time, but it's
difficult to exactly answer the question when you don't necessarily
know exactly what the question is due to incorrect terminology, which
is part of my point.

While it's not necessarily reasonable to expect people to *initially*
frame theirs question in correct terminology, I don't think it's
unreasonable to ask people to *reframe* their questions in correct
terminology in order to help them better, having also helped them to
understand the correct terminology. It's not like I just say, "Your
terminology is wrong, go away."
What happens when someone just talks about the terminology, and not
the main question, is unfortunate and inevitable. In this thread, and
in another thread I started last fall, you ended up sidetracking the
discussion to the point where there is virtually no chance of anyone
replying to the followup question that I asked. That is not helpful.

I pretty much always try to include an answer to the question, while
trying to clarify *exactly* what is meant by the question in the first
place. I don't know which other thread you mean, unfortunately, so I
can't speak for that. Apologies if I didn't answer your question
though. I really do try to.
I mention this in the spirit of trying to get you to think about this
next time. The first response you wrote was helpful to me; the other
ones have been anti-helpful because they sidetracked the discussion.

Even in my second response I was talking about your question, wasn't I?
After that I thought your original question had been answered, and the
posts were only about terminology.
Now, people get to read us going back and forth about something they
could care less about, and possibly they get to read me writing the
same question in another thread, if I want an answer.

Do you think there is actually more to the answer than I've already
given? I've shown why you can't pass an arbitrary unboxed value type by
reference. (I should also mention that you can't pass an arbitrary
unboxed value type by value either, as the stack needs to know the size
of the argument in advance.) I've shown how you can work around that
with boxing, if you're confident that you know the type after the
method call. What more do you need to know?

This discussion is probably best continued by email - feel free to mail
me with a reply. (I'd have sent this by email if I could have done.)
 

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