Home > Blockchain >  Returning tuples from a method results in cumbersome usage pattern
Returning tuples from a method results in cumbersome usage pattern

Time:11-09

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?

CodePudding user response:

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
}

CodePudding user response:

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

  • Related