11

I have just added an out bool parameter to a method I've written in order to get a warning in to my UI. I've used an out rather than getting the method itself to return false/true as that would imply the DoSomething failed/succeeded. My thinking was that the warnUser would indicate what the warning actually was without having to look at the implementation of the method.

Original Code

public void DoSomething(int id, string input);

New Code

public void DoSomething(int id, string input, out bool warnUser);

I'm using Moq to test this code, but it doesn't support out/ref parameters because they're not supported by Lambda expressions

Test Code

mockService.Verify(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<bool>());

So, is using out parameters bad practise and if so what do I do instead?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Antony Scott
  • 21,690
  • 12
  • 62
  • 94

7 Answers7

12

Using an out parameter in a void method is generally a bad idea. You say you've used it "rather than getting the method itself to return false/true as that would imply the DoSomething failed/succeeded" - I don't believe that implication is there. Usually in .NET failure is indicated via an exception rather than true/false.

out parameters are generally uglier to use than return values - in particular, you have to have a variable of the right type to handle, so you can't just write:

if (DoSomething(...))
{
   // Warn user here
}

One alternative you might want to consider is an enum indicating the warning level required. For example:

public enum WarningLevel
{
    NoWarningRequired,
    WarnUser
}

Then the method could return a WarningLevel instead of bool. That would make it clearer what you meant - although you might want to rename things slightly. (It's hard to give advice with metasyntactic names such as "DoSomething" although I entirely understand why you've used that here.)

Of course, another alternative is that you might want more information to be present - like the reason for the warning. That could be done with an enum, or you might want to give some richer result entirely.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I disagree about the implication of failure. if a method has a bool return, to me that implies a return of false means it failed. But I do agree that failure is generally indicated by an exception being thrown (preferably a strongly typed one). It do like the enum idea though, I should have recognised that myself as I've used that approach in the past. thanks. – Antony Scott Nov 23 '10 at 10:57
  • +1 for the `WarningLevel` suggestion. This would eliminate the confusion the asker is concerned about with regards to the return value being interpreted as the success or failure of the function. – Cody Gray - on strike Nov 23 '10 at 10:57
  • 1
    I've accepted this answer as my calling code will be far more readable. "if (!DoSomething(...)" vs "if (DoSomething(...) == WarningLevel.WarnUser)". obviously i'd have something more meaningful that "WarnUser" – Antony Scott Nov 23 '10 at 11:02
9

out is very much a useful construct, in particular in patterns like bool TryGetFoo(..., out value), where you want to know the "if" and the "what" separately (and nullable isn't necessarily an option).

However - in this case, why not just make it:

public bool DoSomething(int id, string input);

and use the return value to signal this?

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    As I said, I didn't want to imply that the "Something" has failed/succeeded – Antony Scott Nov 23 '10 at 10:54
  • 3
    @Marc Gravell I would argue that in .NET 4, using a Tuple might be clearer as the input (method arguments) is separated from the output (return values) and still supplies the "if" and "what". And of course, tuples work just fine in lambdas. – Damian Powell Nov 23 '10 at 10:55
  • 2
    @Antony - I'm not sure I see the significance of that comment; you *do*, however, seem to have exactly one value being returned - why use `out` when you can use `return` for that? – Marc Gravell Nov 23 '10 at 10:55
  • it just doesn't read right to me. i like my code to read naturally if at all possible. and having "if (!DoSomething(...)" looks like a failure to "do something" to me. – Antony Scott Nov 23 '10 at 10:59
  • 3
    @Antony - then consider renaming the method so it *does* make sense; or, frankly, get over it ;p A return value doesn't mean "failure" (this isn't C/C++) - it means "here is the return value". The fact that it is a `bool` is irrelevant. – Marc Gravell Nov 23 '10 at 11:05
  • 1
    @Antony (an `Exception` thrown would mean failure) – Marc Gravell Nov 23 '10 at 11:05
  • I'm with Damian on favouring Tuple. I wish C# would autotranslate that for me like F# does :) Admittedly for TryXXX I may well still use the "standard" pattern simply because these days it *is* a standard pattern :( – Jon Skeet Nov 23 '10 at 11:11
4

A few additional thoughts:

  • What FxCop says: CA1021: Avoid out parameters

  • For private/internal methods (implementation details) out/ref parameters are less of an issue

  • C# 7 Tuples often are a better alternative to out parameters

  • Further, C# 7 improves the handling of out parameter on the call site by introducing "out variables" and by allowing to "discard" out parameters

ulrichb
  • 19,610
  • 8
  • 73
  • 87
2

Given a big Legacy Code Method (say 15+ lines, legacy code methods with 200+ lines are quite common), one might want to use the "Extract Method" refactoring to clean up and make code less brittle and more maintainable.

Such a refactoring is very likely to produce one or more new methods with out parameters for setting variable values local to the prior method.

Personally, I use this circumstance for a strong indicator that there have been one or more descrete classes hiding in the prior method, so that I can use "Extract class", where in the new class those out parameters get properties visible to the calling (prior) method.

I consider it bad practice to leave the extracted methods with out parameters in the prior method, skipping the coherent following step of "Extract Class", because if you skip it, those local variables remain in your prior function, but do semantically no longer belong to it.

So, in such a scenario, out parameters in my opinion are a code smell breaking SRP.

1

This is a really tough question to answer without knowing more about the context.

If DoSomething is a method in the UI layer that is do something which is UI related, then perhaps it's okay. If DoSomething is a business layer method though, then this is probably not a good approach because it implies that the business layer needs to understand what an appropriate response might be, and it might even have to be aware if localization issues.

On a purely subjective note, I've tended to stay away from out parameters. I think they disrupt the flow of the code and make it a little less clear.

Damian Powell
  • 8,655
  • 7
  • 48
  • 58
0

I think that the best way to do this is to use expected Exceptions. You can create a set of custom exceptions that define your warnings, and catch them in the calling method.

public class MyWarningException : Exception() {}

...

try
{ 
     obj.DoSomething(id,input);
}
catch (MyWarningException ex)
{
     // do stuff
}

The idea would be that the exception is raised at the end of the DoSomething implementation, so that the flow doesn't stop in the middle

Daniel Perez
  • 4,292
  • 4
  • 29
  • 54
  • 5
    An exception should only be thrown if the method can't do what it's meant to, IMO. If it's succeeded but for some reason the user should be given a warning, that doesn't sound like an exceptional situation to me. – Jon Skeet Nov 23 '10 at 10:50
  • 3
    @ykatchou actually it isn't *that* slow; but it is not good practice for general logic flow. – Marc Gravell Nov 23 '10 at 10:51
  • I can't use an exception as it would have unwanted side effects on my UI code which calls the DoSomething method. – Antony Scott Nov 23 '10 at 10:55
  • Jon, an exception indicates a behaviour. If you're expecting that behaviour, then it doesn't mean that the method couldn't do its work?? – Daniel Perez Nov 23 '10 at 10:57
  • what side effects? if you're handling the specific exception, then there are no side effects. if the exception is of other type (whatever it is), then it will bubble up in the call stack as it would normally do – Daniel Perez Nov 23 '10 at 11:00
  • @Daniel I apologise for giving more context in my question, but my code already handles exceptions. In the controller code (this is within an MVC website) it redirects to a different action depending on whether an exception was handled or not. – Antony Scott Nov 23 '10 at 11:09
  • @Daniel: Nothing about the context we've been given indicates that this "display a warning to the user" means "failure". True, we don't have many details here - but from what we've been told, exceptions aren't appropriate in this case. – Jon Skeet Nov 23 '10 at 11:12
  • oops, that should have read "I apologise for *not* giving more context in my question" – Antony Scott Nov 23 '10 at 13:23
-1

I think the best best solution for your case is to use a delegate instead of bool. Use something like this:

public void DoSomething(int id, string input, Action warnUser);

You can pass an empty lamda where you don't want to display warnings to user.

Juozas Kontvainis
  • 9,461
  • 6
  • 55
  • 66