ref vs. out: same at runtime, same/different at compiler time?

  • Thread starter Thread starter Zytan
  • Start date Start date
Z

Zytan

MSDN says: "The ref and out keywords are treated differently at run-
time, but they are treated the same at compile time. Therefore methods
cannot be overloaded if one method takes a ref argument and the other
takes an out argument."

But, I think it means they are treated the same at run time, and
treated BOTH different AND the same at compile time: 1. you can't have
two methods that differ only in ref/out (presumably because they are
treated the same at run time), so they appear to be the same at
compile time, and 2, ref/out specifically are handled differently in
terms of when they need to be ininitialized, which is caught at
compile time.

Is that correct?

Zytan
 
1. you can't have
two methods that differ only in ref/out (presumably because they are
treated the same at run time),

No, at run time they are processed by the CLR according to different rules.

2, ref/out specifically are handled differently in
terms of when they need to be ininitialized, which is caught at
compile time.

Not quite. The reason they are treated the same at compile time is that
thier method signatures are the same and this is why you can't overload
them.
 
Zytan said:
MSDN says: "The ref and out keywords are treated differently at run-
time, but they are treated the same at compile time. Therefore methods
cannot be overloaded if one method takes a ref argument and the other
takes an out argument."

I would personally say it's the other way round. They're definitely
treated differently at compile-time - with "out" you can pass in an
uninitialized variable, whereas a ref argument must be initialised.

In the method itself, an out parameter must be initialised in the code
before the method terminates normally (i.e. without an exception)
whereas there's no such restriction for ref.

As far as the runtime is concerned, however, I *believe* that "out"
just adds an attribute to the method for the sake of compilers. I think
that serialization code takes note of it as well, but not the CLR
itself.
 
Scott M. said:
1. you can't have

No, at run time they are processed by the CLR according to different rules.

Could you point out those different rules in the CLI spec? I don't
believe there's any difference.
2, ref/out specifically are handled differently in

Not quite. The reason they are treated the same at compile time is that
thier method signatures are the same and this is why you can't overload
them.

They're not treated the same. Changing "out" for "ref" or vice versa
changes the rules as to what you can and can't do.
 
But you call the method (with out or ref) the same way because of their
signatures being the same. This is what I'm referring to and this is what I
believe the documentation is referring to.

If I'm writing code that calls the method, the compiler would not be able to
tell the difference between the ref and the out method, so it doesn't allow
methods to differ by only this factor. In this regard, they are treated the
same.
 
Hi ,

Jon Skeet said:
I would personally say it's the other way round. They're definitely
treated differently at compile-time - with "out" you can pass in an
uninitialized variable, whereas a ref argument must be initialised.


I agree with you, they may generate the same code (don't know for sure) and
the only difference between then is the extra conditions that an "out" must
comply ( be assigned ).
I do not see how they are treated differently at runtime though.
 
Ignacio Machin ( .NET/ C# MVP ) said:
Hi ,




I agree with you, they may generate the same code (don't know for sure) and the only
difference between then is the extra conditions that an "out" must comply ( be assigned ).
I do not see how they are treated differently at runtime though.

The [Out] attribute set on the argument is used as an "hint" by the "Interop marshaler "in
order to optimize calls into unmanaged code (both COM and C style).

Willy.
 
But you call the method (with out or ref) the same way because of their
signatures being the same. This is what I'm referring to and this is what I
believe the documentation is referring to.

If I'm writing code that calls the method, the compiler would not be able to
tell the difference between the ref and the out method, so it doesn't allow
methods to differ by only this factor. In this regard, they are treated the
same.

Yes, this is what I believe MSDN is referring to when it says they are
the same at compile time.

But, at compile time, ref/out both have different rules of when they
need to be initialized, and since these rules are checked at compile
time, they most definitely are handled differently at compile time.

So, they are the same AND different at compile time, at the same time.

Zytan
 
1. you can't have


No, at run time they are processed by the CLR according to different rules.

Really? I wonder whay would be different about them?

I thought it was like one of those things such as C++'s "const" where
at compile time, it tells you where you're being stupid, but at run
time a "const" variable is just like any other variable (well, within
certain reason, I believe. Maybe that's a bad example).

2, ref/out specifically are handled differently in


Not quite. The reason they are treated the same at compile time is that
thier method signatures are the same and this is why you can't overload
them.

Yes, perhaps I worded it wrong, but this is what I meant by that they
are the same at compile time. But, they are different at compile time
in that there are rules that state when they should be initialized.
ref's need to be initialized before being passed in. out's need to be
initialized only before being passed out.

Zytan
 
MSDN says: "The ref and out keywords are treated differently at run-
I would personally say it's the other way round.

Exactly. I actually read it the other way at first. And went to
quote it, and then realized I was wrong. So, now I'm wondering if
they should explain it better.
They're definitely
treated differently at compile-time - with "out" you can pass in an
uninitialized variable, whereas a ref argument must be initialised.
Exactly.

In the method itself, an out parameter must be initialised in the code
before the method terminates normally (i.e. without an exception)
whereas there's no such restriction for ref.
Yup.

As far as the runtime is concerned, however, I *believe* that "out"
just adds an attribute to the method for the sake of compilers. I think
that serialization code takes note of it as well, but not the CLR
itself.

Ok, I don't know anything about attributes or serialization code.
But, I was thinking that once the final byte code is made, both 'out'
and 'ref' are handled as 'ref', and thus the issue of the compile
complaining if you have two signatures that differ only by out/ref
(which is an issue even before the byte code is made). If they really
were different, then this wouldn't be a problem.

I guess this is an issue of proper documentation. I was happy with
using both ref and out until I read the docs, and then I wondered what
I was missing.

Zytan
 
The [Out] attribute set on the argument is used as an "hint" by the "Interop marshaler "in
order to optimize calls into unmanaged code (both COM and C style).

Ah, so that's where it's different!

Thanks,

Zytan
 
Scott M. said:
But you call the method (with out or ref) the same way because of their
signatures being the same. This is what I'm referring to and this is what I
believe the documentation is referring to.

If I'm writing code that calls the method, the compiler would not be able to
tell the difference between the ref and the out method, so it doesn't allow
methods to differ by only this factor. In this regard, they are treated the
same.

The compiler most certainly *can* tell the difference:

using System;

class Test
{
static void Main()
{
int x;
Foo (out x);
}

static void Foo (ref int x)
{
}
}

Test.cs(8,9): error CS1502: The best overloaded method match for
'Test.Foo(ref
int)' has some invalid arguments
Test.cs(8,18): error CS1620: Argument '1' must be passed with the
'ref' keyword


If the method is declared to have an "out" parameter, the compiler will
stop you from using it without specifying "out" at the call site, and
the same with ref.

So yes, it does make a difference at compile-time.

Now, what runtime difference do you believe it makes?
 
Zytan said:
The [Out] attribute set on the argument is used as an "hint" by the
"Interop marshaler "in
order to optimize calls into unmanaged code (both COM and C style).

Ah, so that's where it's different!

But only for interop calls... whereas they certainly *are* different at
compile-time, regardless of whether it's an interop call or a "normal"
call.
 
If the method is declared to have an "out" parameter, the compiler will
stop you from using it without specifying "out" at the call site, and
the same with ref.

Only with C#.

C++/CLI makes the call with no keyword needed. Reflection.Emit also calls
either variant the same way.

In fact, both have the same type (using System.Type.MakeByRefType), the
difference is an attribute (System.Runtime.InteropServices.OutAttribute) or
the absence thereof.
So yes, it does make a difference at compile-time.

Now, what runtime difference do you believe it makes?

For in-process code, none at all. For COM, remoting, etc, the runtime can
save copying an empty out-only buffer.
 
Zytan said:
Really? I wonder whay would be different about them?

I thought it was like one of those things such as C++'s "const" where
at compile time, it tells you where you're being stupid, but at run
time a "const" variable is just like any other variable (well, within
certain reason, I believe. Maybe that's a bad example).

That's a bad example, because C++ const globals can sometimes be placed in a
readonly segment of memory, where you'll get an actual access violation if
you try to write them (see people writing to string literals, for example).
 
Ben Voigt said:
Only with C#.

Sure. I have to admit I assumed that we were talking about the C#
compiler here.
C++/CLI makes the call with no keyword needed. Reflection.Emit also calls
either variant the same way.

In fact, both have the same type (using System.Type.MakeByRefType), the
difference is an attribute (System.Runtime.InteropServices.OutAttribute) or
the absence thereof.
Absolutely.


For in-process code, none at all. For COM, remoting, etc, the runtime can
save copying an empty out-only buffer.

Yup, that's true.
 
Really? I wonder whay would be different about them?
That's a bad example, because C++ const globals can sometimes be placed in a
readonly segment of memory, where you'll get an actual access violation if
you try to write them (see people writing to string literals, for example).

Yes! And that's precisely why I said maybe it's a bad example! Then
I thought to explain all of that is longer than the example itself :)
And there's even more, such as constants used by the preprocessor, for
setting the size of arrays, etc.

Zytan
 

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

Back
Top