41

How to check if a System.ValueTuple is default? Rough example:

(string foo, string bar) MyMethod() => default;

// Later
var result = MyMethod();
if (result is default){ } // doesnt work

I can return a default value in MyMethod using default syntax of C# 7.2. I cannot check for default case back? These are what I tried:

result is default
result == default
result is default(string, string)
result == default(string, string)
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • 4
    Instead of returning a "default" tuple, return a tuple with a result flag and check the flag. That's one of the most common scenarios. Besides, `is` is meant for casting or pattern matching. In this case you are asking for *equality* – Panagiotis Kanavos Apr 30 '18 at 12:37
  • 7
    Once C# gets its ["Support for == and != on tuple types"](https://github.com/dotnet/csharplang/issues/190), `result == default((string, string))` (edit: extra parentheses are needed) and perhaps even `result == default` should work, but we're not there yet. –  Apr 30 '18 at 12:44
  • @PanagiotisKanavos returning a flag is doable. Just wondering about latest syntax. Regarding `is`, it does work with compile time constants for equality check as far as I know, including `default(T)`. – nawfal Apr 30 '18 at 12:46
  • @nawfal tuples were added so we *don't* have to write such code. What does this default tuple mean? That the method failed? That the field values are missing? Or that the field values are null? What about nullable tuples? What is this code going to do when you migrate it to C# 8 ? – Panagiotis Kanavos Apr 30 '18 at 12:47
  • 1
    @PanagiotisKanavos Just assume developer may not have much control over what is being returned from a public method. As to what it means, it means the operation didnt succeed in returning a meaningful value and just gloss over. As I said previously the spirit of the question is learning C# syntax. – nawfal Apr 30 '18 at 12:58
  • 1
    @PanagiotisKanavos It doesn't have to be directly related to a known value tuple. For example if you use a generic method that does something, and sometimes returns default (which is totally correct for scenarios like "give me the first match, if there is one"), what happens if the data that was searched (the generic type) is a value tuple? That's a real use case. – Wolfsblvt Jun 18 '19 at 18:06
  • 2
    @Wolfsblvt that use case is no different than returning a null, 0 or other magic value. Value tuples solve that among other things, by allowing the use of Rust- or Go-like value tuples. Instead of returning nulls or magic values and checking for null or default, return a strongly typed (result,error) tuple. It's harder to ignore errors this way – Panagiotis Kanavos Jun 19 '19 at 07:36

5 Answers5

52

If you really want to keep it returning default, you could use

result.Equals(default)

the built-in Equals method of a ValueTuple should work.

As of C# 7.3 value tuples now also support comparisons via == and != fully, Meaning you can now also do

result == default and it should work the same.

Gibbon
  • 2,633
  • 1
  • 13
  • 19
13

There are several ways of comparing default values to a value tuple:

    [TestMethod]
    public void Default()
    {
        (string foo, string bar) MyMethod() => default;
        (string, string) x = default;

        var result = MyMethod();

        // These from your answer are not compilable
        // Assert.IsFalse(x == default);
        // Assert.IsFalse(x == default(string string));
        // Assert.IsFalse(x is default);
        // Assert.IsFalse(x is default(string string));

        Assert.IsFalse(Equals(x, default));
        Assert.IsFalse(Equals(result, default));

        Assert.IsTrue(Equals(x, default((string, string))));
        Assert.IsTrue(Equals(result, default((string, string))));
        Assert.IsTrue(result.Equals(default));
        Assert.IsTrue(x.Equals(default));
        Assert.IsTrue(result.Equals(default((string, string))));
        x.Equals(default((string, string)))
    }

A simple defaultbefore it's used in a comparison must be reified from its "pure" null to a value tuple with default values for the members.

Here's what I have under the debugger:

enter image description here

Kit
  • 20,354
  • 4
  • 60
  • 103
  • Thanks for detailed answer. In the last line I think you meant `x.Equals(default((string, string)))` instead of `Equals(x, default((string, string)))`. – nawfal Apr 30 '18 at 16:00
  • Actually both of those cases pass. – Kit May 01 '18 at 13:31
  • 1
    I know both pass, but you have duplicated `Equals(x, default((string, string)))` twice. Just saying. – nawfal May 01 '18 at 19:59
8

As of C# 7.3, tuple types now support == and !=. So your code could look like this:

(string foo, string bar) MyMethod() => default;

// Later
var result = MyMethod();
if (result == default){ } // Works!

See https://learn.microsoft.com/en-us/dotnet/csharp/tuples#equality-and-tuples

phillhutt
  • 183
  • 1
  • 5
6

There are two problems with your attempts:

  1. There is no == operator defined on tuples (in C# 7.2)
  2. To get a default value for a tuple type, you need to parenthesize the type properly: default((int, int))

Note that an == operator is added to tuples in C# 7.3. Then you can do tuple == default (see live example).

Julien Couvreur
  • 4,473
  • 1
  • 30
  • 40
1

Noticed a dearth of code and docs in answers, so I tried out a few different equality checks in .NET 5, all with ==, to see how they'd evaluate. Elucidating.

The bottom line seems to be if all individual values in the tuple are their own versions of default, the tuple is default. And if you new up a tuple to = default everything is set to its own version of default.

That just kind of makes sense.

Actual code1

NOTE: This test was performed in a .NET 5 console app.

static void TupleDefault()
{
    (int first, string second) spam = new(1, "hello");
    (int first, string second) spam2 = default;

    Console.WriteLine(spam == default);      // False
    Console.WriteLine(spam2 == default);     // True

    Console.WriteLine(spam2.first);          // 0
    Console.WriteLine(spam2.first == 0);     // True

    Console.WriteLine(spam2.second);         // Nothing.
    Console.WriteLine(spam2.second == null); // True

    // ==== Let's try to create a default "by hand" ====
    (int first, string second) spam3 = new(0, null);

    // It works!
    Console.WriteLine(spam3 == default);     // True
}
ruffin
  • 16,507
  • 9
  • 88
  • 138