Check if value tuple is default
Asked Answered
E

5

46

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)
Emee answered 30/4, 2018 at 12:35 Comment(7)
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 equalityWait
Once C# gets its "Support for == and != on tuple types", result == default((string, string)) (edit: extra parentheses are needed) and perhaps even result == default should work, but we're not there yet.Cellist
@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).Emee
@Emee 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 ?Wait
@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.Emee
@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.Canon
@Canon 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 wayWait
M
56

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.

Marked answered 30/4, 2018 at 12:44 Comment(0)
I
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

Inflectional answered 30/4, 2018 at 12:52 Comment(3)
Thanks for detailed answer. In the last line I think you meant x.Equals(default((string, string))) instead of Equals(x, default((string, string))).Emee
Actually both of those cases pass.Inflectional
I know both pass, but you have duplicated Equals(x, default((string, string))) twice. Just saying.Emee
D
10

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

Dubrovnik answered 7/12, 2018 at 19:6 Comment(0)
S
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).

Stereophonic answered 1/5, 2018 at 18:40 Comment(2)
I dont think point 2 is correct. default is a substitute for default(T).Emee
@Emee Sorry I wasn't clear. I was referring to default(string, string) which is invalid syntax (it is missing parens).Stereophonic
S
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
}
Sinfonia answered 12/10, 2021 at 14:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.