2

I've been playing with returning tuples from methods, so method signatures like this...:

private int GetAlpha() {...} // -1 indicates an error
private bool GetAlpha(out int alphaOut) {...}

...turn into this:

private (bool Success, int Alpha) GetAlpha() {...}

PROS:

  • I like avoiding the use of out-of-band values like -1 to signal an error to the caller
  • I've been reading recently that out parameters are evil and to be avoided

CONS:

  • I can only use the var (success, a, b, ...) = Foo(...) syntax ONCE in a typical method. Thereafter, I'm forced to declare nearly all variables in the returned tuple, because 'success' is already defined
  • I not only have to declare return variables, but I also have to explicitly specify their type (vs. implicitly using var).
var (success, alpha) = GetAlpha();
if (success)
{
    //var (success, beta, gamma) = GetStuff(alpha);      // ERROR - 'success' is already defined

    //(success, beta, gamma) = GetStuff(alpha);          // ERROR - 'beta' and 'gamma' are undefined

    //(success, var beta, var gamma) = GetStuff(alpha);  // ERROR - no such syntax, silly!

    string beta;
    DateTime gamma;
    (success, beta, gamma) = GetStuff(alpha);
        .
        .
        .

The convenience and conciseness of using the implicit declaration and typing is so nice, that it bugs me I'm typically only able to use it once in a method.

Am I missing anything? Is there some other pattern that avoids this?

5
  • 1
    This is a limitation of the deconstruction syntax in the older C# version. I believe what you're looking for exists starting in C# 10. What are you working in that has you stuck in 7.0? Commented Nov 9, 2022 at 4:55
  • Your second syntax works fine here: dotnetfiddle.net/UJvDRE (I realize it's a different C# version) Commented Nov 9, 2022 at 4:59
  • 1
    @Wyck - you used the same two variables in both calls. I'm always using "success", but the other return variables are new for each subsequent call. Commented Nov 10, 2022 at 1:40
  • 1
    OK I get what you're tying to do now. I wrote an answer. Commented Nov 10, 2022 at 5:05
  • Thank you @Logarr, I think yours is the correct answer for me. I'm going to re-examine why we're using the version of C# we are (our app only targets Win 10/11, so I'm guessing the latest version should be OK). Commented Nov 10, 2022 at 19:05

3 Answers 3

2

I think there's an argument to be made that it's dangerous to reuse variables the way you're trying to. I'd personally prefer to see this:

var (alphaSucceeded, alpha) = GetAlpha();
if (alphaSucceeded)
{
    var (getStuffSucceeded, beta, gamma) = GetStuff(alpha);

There are many ways to solve this kind of problem.

For example, you could use a monadic library (there are many out there: this is mine) to represent the concept of GetAlpha() returning a non-value.

var alphaMaybe = MaybeGetAlpha();
var stuff = alphaMaybe.Select(alpha => GetStuff(alpha)); // or just.Select(GetStuff)

Or, since you're currently only dealing with value types, you could just use Nullable<>s. In later versions of C#, you can use nullables with reference types, and also use pattern matching to simplify syntax.

if(GetAlpha() is int alpha)
{
  // use alpha
}
Sign up to request clarification or add additional context in comments.

Comments

1

With judicious use of discards (assigning an underscore _ as the variable name) you can do it. And you only need C# 7. Put new variables in the first tuple and existing variables in the second tuple. The syntax is longer, but still DRY.

Which, by the way, stands for Don't Repeat Yourse... omg the irony, nevermind. ;)

var (success, alpha) = GetAlpha();
if (success)
{
    var (_, beta, gamma) = (success, _, _) = GetStuff(alpha);  
}

Comments

0

I would argue this particular case - where you are interested if the call is successful or not - is a case where out is best suited.

private bool GetAlpha(out int alphaOut) {...}

I would use the tuple approach only if I'm not interested in the success state.

private (int, string) GetAlpha() {}

If I need the success state AND I need multiple returns, then I would use both so that I don't have multiple out params - which I think is your concern.

private bool GetAlpha(out (int, string) tupleAlpha) {...}

BTW, I don't think there is anything wrong with out. Yes, if you are using it with void methods its unnecessary, or if you are returning multiple out (but that's more of a code smell indicating your function is doing too many things). There are plenty of examples of the out pattern in the .NET API.

https://learn.microsoft.com/en-us/dotnet/api/system.int32.tryparse?view=net-6.0

1 Comment

While out params aren't "evil" per se, they do pose problems when it comes to modern patterns like LINQ and Tasks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.