Peter - Reinstate Monica
Peter - Reinstate Monica

Reputation: 16039

Can one call `operator true()` explicitly? When is it used to convert to bool?

Out of curiosity, I explored overloading operators in C#. There is an interesting post by Eric Lippert discussing the design decisions in C++ and C# concerning operator&&. In C# its overloads are defined implicitly by overloading operator& plus overloading the boolean operators trueand false, which allows the language to preserve the sometimes essential short-circuit semantics.

Playing with the somewhat exotic operator true() and false() I found that I was not able to call them directly. Instead, they are implicitly called in certain places where a bool is required. As far as I can see, these are the language constructs which directly require a bool, namely the ternary conditionaly operator and the if clause, plus calls to operator&& resp. || when the argument type has overloaded operators & resp. |.

Edit: The book "The C# Programming Language" (7.11) as well as the annotated C# Standard in 14.11.2 -- both found via google search result -- have a code example with a direct operator call which I didn't understand must be pseudo code. I tried to replicate that.

As an aside, it is harder to provoke a call to operator false(); the ternary conditional as well as an if clause always test by calling operator true(). It seems as if the only way to call it is by calling operator||().

The motivation to call the boolean operators explicitly is that it would be nice to define only one of them directly and define the other one in terms of that, so that the definitions are always consistent. Below is a little example program with a few things I tried. Is there a syntax which I missed?

using System;

namespace TriviallyTrue
{
    public class T
    {
        public static bool operator true(T t) { Console.WriteLine("In op. true");  return true; }
        public static bool operator false(T t) { return true; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            T t = new T();
            // bool b = T.true(t); // Identifier expected; 'true' is a keyword

            // ok, I see. Let's use the keyword syntax.
            // bool b = T.@true(t); //'TriviallyTrue.T' does not contain a definition for 'true'
                            // That's so not true!

            // oh. perhaps we need to use cast syntax, akin to invoking operator int()?
            // bool b = (true)t; // ; expected

            // hm. It's in T's namespace...
            // bool b = (T.true)t; // Identifier expected;
                    // we know that.

            // another cast try.
            // bool b = (T.@true)t; // The type name 'true' does not exist in the type 'TriviallyTrue.T'
                    // ah, a type is expected. Well, the type is bool, right? But casting to bool
                    // doesn't work either, see below and in Main().

            // bool b = (T.@bool)t; // The type name 'bool' does not exist in the type 'TriviallyTrue.T' 
                    // well, it exists *some*what




            if (t) // works
            {
                // Console.WriteLine("t was " + (bool)t); // Cannot convert type 'TriviallyTrue.T' to 'bool'
                            // That's so not true!
                Console.WriteLine("t was " + (t ? "True" : "False" )); // works!
            }
        }
    }
}

Sample session:

In op. true
In op. true
t was True

Upvotes: 3

Views: 929

Answers (2)

Ivan Stoev
Ivan Stoev

Reputation: 205729

I cannot answer the question in the title, but I think I can cover this part

The motivation to call the boolean operators explicitly is that it would be nice to define only one of them directly and define the other one in terms of that, so that the definitions are always consistent.

Without questioning in any way what @Eric Lippert wrote in that post, C# has an easier way of doing all that when a one of the true or false is logically the inverse on the other, which is the most common practical case. Instead of overriding 4 operators (false, true, & and |), one can simply provide a single implicit conversion to bool.

For instance

public class T
{
    public static implicit operator bool(T t) { return t != null; }
}

Now all these work

T a = new T(), b = null;
if (a) { }
if (!a) { }
if (b) { }
if (!b) { }
if (a && b) { }
if (b && a) { }
if (a & b) { }
if (a || b) { }
if (b || a) { }
if (a | b) { }
var c1 = a ? 1 : 0;
var c2 = b ? 1 : 0;

Upvotes: 4

user743382
user743382

Reputation:

You can't call any operator methods explicitly in C#. operator true and operator false are no exception. It's just that most operator methods have a more straightforward method of invoking them implicitly.

If it makes sense to call the operator method in other scenarios than as an overload operator, provide it as a regular method instead. It's generally more readable and can nicely avoid the whole problem of having multiple separate implementations that you wanted to solve.

public class T
{
    private bool asBoolean() { ... } // or even make it public
    public static bool operator true(T t) { return t.asBoolean(); }
    public static bool operator false(T t) { return !t.asBoolean(); }
}

For completeness, you can implement operator false as e.g.

public static bool operator false(T t) { return t ? false : true; }

but please don't unless you absolutely need to.

Upvotes: 2

Related Questions