tags:

views:

838

answers:

11

Both in SQL and C#, I've never really liked output parameters. I never passed parameters ByRef in VB6, either. Something about counting on side effects to get something done just bothers me.

I know they're a way around not being able to return multiple results from a function, but a rowset in SQL or a complex datatype in C# and VB work just as well, and seem more self-documenting to me.

Is there something wrong with my thinking, or are there resources from authoritative sources that back me up? What's your personal take on this and why? What can I say to colleagues that want to design with output parameters that might convince them to use different structures?

EDIT: interesting turn- the output parameter I was asking this question about was used in place of a return value. When the return value is "ERROR", the caller is supposed to handle it as an exception. I was doing that but not pleased with the idea. A coworker wasn't informed of the need to handle this condition and as a result, a great deal of money was lost as the procedure failed silently!

+21  A: 

Output parameters can be a code smell indicating that your method is doing too much. If you need to return more than one value, the method is likely doing more than one thing. If the data is tightly related, then it would probably benefit from a class that holds both values.

Of course, this is not ALWAYS the case, but I have found that it is usually the case.

In other words, I think you are right to avoid them.

Brian Genisio
A: 

I generally never use them, I think they are confusing and too easy to abuse. We do occasionally use ref parameters but that has more to do with passing in structures vs. getting them back.

Joe
A: 

Your opinion sounds reasonable to me.

Another drawback of output parameters is the extra code needed to pass results from one function to another. You have to declare the variable(s), call the function to get their values, and then pass the values to another function. You can't just nest function calls. This makes code read very imperatively, rather than declaratively.

Nat
+8  A: 

Bob Martin wrote about this Clean Code. Output params break the fundamental idea of a function.

output = someMethod(input)

Jarrett Meyer
A stored proc is not a function though, but I understand the reasoning
gbn
+1  A: 

I think they're useful for getting IDs of newly-inserted rows in the same SQL command, but i don't think i've used them for much else.

CodeByMoonlight
A: 

C++0x is getting tuples, an anonymous struct-like thing, whose members you access by index. C++ programmers will be able to pack multiple values into one of those and return it. Does C# have something like that? Can it return an array, perhaps, instead? But yeah output parameters are a bit awkward and unclear.

JDonner
C# can return an array easily. But returning an array (which is essentially what the tuple is as well) seems to me quite non-semantic, and can easily get confusing. If you always return the same set of values, then out variables seem a better choice to me.
Vilx-
C# 4.0 will be introducing a very innovative feature... the Tuple :)
Brian Genisio
Gotta love it! :P
Vilx-
.NET 4.0 has `Tuple` class, but there's no language support for it. C++0x doesn't have any either, but it has language constructs to cover up for it to provide, for example, tuple deconstruction. For example, with C++0x tuples, you can do: `tuple<int, int> t; int a, b; tie(a, b) = t;`. In C#, you'll have to do: `a = t.Item1; b = t.Item2`.
Pavel Minaev
+17  A: 

They have their place. Int32.TryParse method is a good example of an effective use of an out parameter.

bool result = Int32.TryParse(value, out number);
if (result)
{
    Console.WriteLine("Converted '{0}' to {1}.", value, number);         
}
Andrew Cowenhoven
Good example. The TryParse is one of the only methods I've ever seen that uses out *and* is justified in doing so.
Jagd
That's an interesting special case, because TryParse() exists to avoid the possibility of an exception when value does not contain an int.
JeffH
I'd personally prefer "int? Int32.TryParse(string value)" as the signature, because then you can use the ?? operator to specify fallback values. But this function was written before Nullables were introduced.
Jimmy
I disagree... Int32.TryParse() should return an int? Any Try* method should return a nullable type... it reads better and it is easier to use. I create extension methods for string that do exactly that. "1".AsInt(), "1.5".AsDouble(), "true".AsBool() etc
Brian Genisio
There is no fundamental difference between returning an `int?`, and returning an `int`+`bool` combo (one of which goes in an `out` parameter). It's mostly just a matter of convenience.
Pavel Minaev
@Pavel: I think the significant difference is that with an out parameter, the variable needs to be declared separately. Any chance I have to reduce the number of temporary variables is a chance to make my code more readable, which is a win in my books :)
Brian Genisio
Actually, Int32.TryParse showed up in .NET 2.0, at the same time as Nullable<T>, which makes it all the more puzzling that they don't work together. But you can always write your own function to do so.
Kyralessa
Another example is Dictionary<,>.TryGetValue
ChrisW
Even with "int? Int32.TryParse(string value)" you still have to write a variable beforehand to do stuff like if(int.TryParse(...) { .. .}, but now you have to do a null check "int? res = int.TryParse(...); if (res != null) so both implementations have their advantages.
Pop Catalin
Most of the time when I've needed to check if a string parsed correctly to another type, I cared about the value as well. So, I see no value in using this bool TryParse(out) business. Even in the rare case you didn't care about the value and wanted to write ugly code, if(int.TryParse(s).HasValue) would work just fine.
Stuart Branham
A: 

I too see very little use of out/ref parameters, although in SQL it sometimes is easier to pass a value back by a parameter than by a resultset (which would then require the use of a DataReader, etc.)

Though, as luck would have it, I just created one such rare function in C# today. It validated a table-like data structure and returned the number of rows and columns in it (which was tricky to calculate because the table could have rowspans/colspans like in HTML). In this case the calculation of both values was done at the same time. Separating it into two functions would have resulted in double the code, memory and CPU time requirements. Creating a custom type just for this one function to return also seems like an overkill to me.

So - there are times when they are the best thing, but mostly you can do just fine without them.

Vilx-
+1  A: 

The OUTPUT clause in SQL Server 2005 onwards is a great step forward for getting any field values for rows affected by your DML statements. Ithink that there are a lot of situations where this does away with output parameters.

In VB6, ByRef parameters are good for passing ADO objects around.

other than those two specific cases that come to mind, I tend to avoid using them.

Russ Cam
+1  A: 

In SQL only...

Stored procedure output parameters are useful.

  1. Say you need one value back. Do you "create #table, insert... exec, select @var = ". Or use an output parameter?

  2. For client calls, an output parameter is far quicker than processing a recordset.

  3. Using RETURN values is limited to signed integer.

  4. Easier to re-use (eg a security check helper procedure)

  5. When using both: recordsets = data, output parameters = status/messages/rowcount etc

  6. Stored procedures recordset output can not be strongly typed like UDFs or client code

  7. You can't always use a UDF (eg logging during security check above)

However, as long as you don't generally use the same parameter for input and output, then until SQL changes completely your options are limited. Saying that, I have one case where I use a paramter for in and out values, but I have a good reason.

gbn
A: 

My Two Cents:
I agree that output parameters are a concerning practice. VBA is often maintained by people very new to programming and if someone maintaining your code fails to notice that a parameter is ByRef they could introduce some serious logical errors. Also it does tend to break the Property/Function/Sub paradigm.
Another reason that using out parameters is bad practice is that if you really do need to be returning more than one value, chances are that you should have those values in a data structure such as a class or a User Defined Type.
They can however solve some problems. VB5 (and therefore VBA for Office 97) did not allow for a function to return an array. This meant anything returning or altering an array would have to do so via an "out" parameter. In VB6 this ability has been added, but VB6 still forces array parameters to be by reference (to prevent excessive copying in memory). Now you can return a value from a function that alters an array. But it will be just a hair slow (due to the acrobatics going on behind the scenes); it can also confuse newbies into thinking that the array input will not be altered (which will only be true if someone specifically structured it that way). So I find that if I have a function that alters an array it reduces confusion to just use a sub instead of a function (and it will be a tiny bit faster too).
Another possible scenario would be if you are maintaining code and you want to add an out value without breaking the interface you can add an optional out parameter and be confident you won't be breaking any old code. It's not good practice, but if someone wants something fixed right now and you don't have time to do it the "right way" and restructure everything, this can be a handy addition to your tool box.
However if you are developing things from the ground up and you need to return multiple values you should consider:
1. Breaking up the function.
2. Returning a UDT.
3. Returning a Class.

Oorang