Home > OS >  Value tuples exist, so why use the "out" parameter modifier?
Value tuples exist, so why use the "out" parameter modifier?

Time:10-16

Microsoft's documentation for the out parameter modifier points out the following:

Declaring a method with out arguments is a classic workaround to return multiple values. Consider value tuples for similar scenarios.

This strikes me as a remarkably good point. What use case remains for out, now that we have value tuples?

CodePudding user response:

One major use case I can think of off the top of my head are Try... methods that return a value and a boolean so that you can check whether the action succeded or not:

// With out parameters:
if(int.TryParse(someString, out int result)){
   // do something with the int
}

// With tuples:
var (success, value) = int.TryParseWithTuples(someString);
if(success){
   // do something with the int
}

With the out parameter, the notation is cleaner and results in less lines (and doesn't require you to create a local variable for the success boolean). It also allows you to do this:

if(int.TryParse(someString, out int r1)){
   // do something with the int
} else if(int.TryParse(fallbackString, out int r2)){
   // do something with the fallback int
} else {
   throw new InvalidOperationException();
}

With tuples, this would look like this:

var (success, value) = int.TryParseWithTuples(someString);
if(success){
   // do something with the int
} else {
   (success, value) = int.TryParseWithTuples(fallbackString);
   if(success){
       // do something with the fallback int
   } else {
       throw new InvalidOperationException();
   }
}

CodePudding user response:

In addition to the ease of use of the TryX pattern, as pointed out by ascpixi, another case that makes a value-tuple unsuitable as a return type is when one of the two values is a reference. For example take a look at the CollectionsMarshal.GetValueRefOrAddDefault API:

public static ref TValue? GetValueRefOrAddDefault<TKey,TValue> (
    Dictionary<TKey,TValue> dictionary,
    TKey key,
    out bool exists);

It is used like this:

ref int refValue = ref CollectionsMarshal.GetValueRefOrAddDefault(
    dictionary, key, out bool exists);

if (!exists) refValue = 1; else refValue  ;

The ValueTuple<T1, T2> is not a ref struct, so it could not be used for this API. Theoretically this API could return a custom tuple-like ref struct, but in that case it would lack the language support that exists only for real value-tuples, like the shorthand notation with parentheses etc.

CodePudding user response:

As a semi-escoteric case, there may be cases where the size of a tuple may have different passing semantics compared to an out. Sharplab shows different ASM for out vs ValueTuple which tends me towards thinking there are performance-sensitive cases where out would be better.

Another case that comes to mind, before 'named tuples' became a thing, was that the signature with out args could be more descriptive as to the values.

As the docs suggest, normally modern, 'named' ValueTuples are very composable and often great for app-level behavior. But for the reasons mentioned above, it was easier to make compiler sugar around some constructs for transition's sake.

  • Related