tags:

views:

1361

answers:

10

There are a number of questions already on the definition of "ref" and "out" parameter but they seem like bad design. Are there any cases where you think ref is the right solution?

It seems like you could always do something else that is cleaner. Can someone give me an example of where this would be the "best" solution for a problem?

+1  A: 

I think the best uses are those that you usually see; you need to have both a value and a "success indicator" that is not an exception from a function.

Fredrik Mörk
But wouldn't that be the perfect candidate for `out` parameters? `out` seems much clearer to me than `ref` and it is also preferred in the BCL (like in the `<type>.TryParse` methods).
0xA3
So true. I obviously need to sleep now, it's late here... ;)
Fredrik Mörk
+8  A: 

In my opinion, ref largely compensated for the difficulty of declaring new utility types and the difficulty of "tacking information on" to existing information, which are things that C# has taken huge steps toward addressing since its genesis through LINQ, generics, and anonymous types.

So no, I don't think there are a lot of clear use cases for it anymore. I think it's largely a relic of how the language was originally designed.

I do think that it still makes sense (like mentioned above) in the case where you need to return some kind of error code from a function as well as a return value, but nothing else (so a bigger type isn't really justified.) If I were doing this all over the place in a project, I would probably define some generic wrapper type for thing-plus-error-code, but in any given instance ref and out are OK.

mquander
I agree with the idea of making wrapper types if it seems as if the "return code+value" construct is used extensively in a project.
Fredrik Mörk
A: 

The real use for this is when you create a struct. Structs in C# are value types and therefore always are copied completely when passed by value. If you need to pass it by reference, for example for performance reasons or because the function needs to make changes to the variable, you would use the ref keyword.

I could see if someone has a struct with 100 values (obviously a problem already), you'd likely want to pass it by reference to prevent 100 values copying. That and returning that large struct and writing over the old value would likely have performance issues.

Will Eddins
It's not quite redundant in the case of a reference type, because when you pass using 'ref', the function that gets the variable can change your reference to point to a totally different one (or to null.) If you didn't use 'ref', it could only mutate the existing instance of your thing.
mquander
@mquander Would the ref keyword really be necessary to do that? I would think you could do that without the 'ref'
Will Eddins
This information is wrong! In C# references are passed by value by default. See http://www.yoda.arachsys.com/csharp/parameters.html
0xA3
As detailed in divo's link, the 'ref' keyword is indeed necessary to do that. If you don't use the 'ref' keyword, what you actually have are two separate references to the same object. So, changes to the object will be visible from outside the function, but not changes to the reference (i.e. nulling it.)
mquander
@Guard: I removed the incorrect parts from your answer to avoid confusion. Feel free to revert and edit :-)
0xA3
Information about the struct with 100 values is incorrect. A struct (also when preceded with ref) is still copied to the top of the stack, for the called method to do its job. The ref keyword only says that the struct should be copied back again after the called method has finished its job. In your case, I'd go for a reference type object (where only the reference is passed on)
taoufik
@taoufik: Do you have a reference that structs passed with ref are copied? According to the C# spec the following holds: "The argument passed for a reference parameter must be a variable, and during execution of the method, the reference parameter represents the same storage location as the argument variable." (cf. 1.6.6.1 Parameters of http://download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc)
0xA3
+2  A: 

What if you wanted to return multiple objects, that for some unknown reason are not tied together into a single object.

void GetXYZ( ref object x, ref object y, ref object z);

EDIT: divo suggested using OUT parameters would be more appropriate for this. I have to admit, he's got a point. I'll leave this answer here as a, for the record, this is an inadaquate solution. OUT trumps REF in this case.

John MacIntyre
I think in most of these cases you could redesign your code to either group similar things together into better types, or to return each thing independently in an clearer and hopefully still efficient way.
mquander
@mquander-Totally agree. I kind of think if you are doing this, you either have a method that maybe doing too much, or a bad object model. Having said that, I'm sure somebody has done this for a good reason.
John MacIntyre
I would prefer `out` parameters in this case because the intention is much clearer then.
0xA3
@divo-Yeah, maybe you're right.
John MacIntyre
Well, the difference is that "an argument passed to a ref parameter must first be initialized. This differs from out, whose arguments do not have to be explicitly initialized before they are passed" (see http://msdn.microsoft.com/en-us/library/t3c3bfhx.aspx)
0xA3
+4  A: 

P/Invoke is the only place I can really think of a spot where you must use ref or out. Other cases, they can be convenient, but like you said, there is generally another, cleaner way.

JP Alioto
+6  A: 

One area is in the use of small utility functions, like :

void Swap<T>(ref T a, ref T b) { T tmp = a; a = b; b = tmp; }

I don't see any 'cleaner' alternatives here. Granted, this isn't exactly Architecture level.

Henk Holterman
A: 

The obvious reason for using the "ref" keyword is when you want to pass a variable by reference. For example passing a value type like System.Int32 to a method and alter it's actual value. A more specific use might be when you want to swap two variables.

public void Swap(ref int a, ref int b)
{
   ...
}

The main reason for using the "out" keyword is to return multiple values from a method. Personally I prefer to wrap the values in a specialized struct or class since using the out parameter produces rather ugly code. Parameters passed with "out" - is just like "ref" - passed by reference.

public void DoMagic(out int a, out int b, out int c, out int d)
{
   ...
}
Patrik
+6  A: 

Well, ref is generally used for specialized cases, but I wouldn't call it redundant or a legacy feature of C#. You'll see it (and out) used a lot in XNA for example. In XNA, a Matrix is a struct and a rather massive one at that (I believe 64 bytes) and it's generally best if you pass it to functions using ref to avoid copying 64 bytes, but just 4 or 8. A specialist C# feature? Certainly. Of not much use any more or indicative of bad design? I don't agree.

JulianR
+1  A: 

One design pattern where ref is useful is a bidirectional visitor.

Suppose you had a Storage class that can be used to load or save values of various primitive types. It is either in Load mode or Save mode. It has a group of overloaded methods called Transfer, and here's an example for dealing with int values.

public void Transfer(ref int value)
{
    if (Loading)
        value = ReadInt();
    else
        WriteInt(value);
}

There would be similar methods for other primitive types - bool, string, etc.

Then on a class that needs to be "transferable", you would write a method like this:

public void TransferViaStorage(Storage s)
{
    s.Transfer(ref _firstName);
    s.Transfer(ref _lastName);
    s.Transfer(ref _salary);
}

This same single method can either load the fields from the Storage, or save the fields to the Storage, depending what mode the Storage object is in.

Really you're just listing all the fields that need to be transferred, so it closely approaches declarative programming instead of imperative. This means that you don't need to write two functions (one for reading, one for writing) and given that the design I'm using here is order-dependent then it's very handy to know for sure that the fields will always be read/written in identical order.

The general point is that when a parameter is marked as ref, you don't know whether the method is going to read it or write to it, and this allows you to design visitor classes that work in one of two directions, intended to be called in a symmetrical way (i.e. with the visited method not needing to know which direction-mode the visitor class is operating in).

Comparison: Attributes + Reflection

Why do this instead of attributing the fields and using reflection to automatically implement the equivalent of TransferViaStorage? Because sometimes reflection is slow enough to be a bottleneck (but always profile to be sure of this - it's hardly ever true, and attributes are much closer to the ideal of declarative programming).

Daniel Earwicker
A: 

Personally I would prefer generic tuples instead of ref and out parameters.

Morten