Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does overloaded false operator ever gets executed and what is it good for?

I've been searching for actual working code where an overloaded false operator actually gets executed.

This question (What's the false operator in C# good for?) is somewhat the same, but the accepted answer links to an url which is returning a 404 error. I've also looked at How does operator overloading of true and false work? and some other questions.

What I've found in almost all answers is that false only gets executed when you use a short circuited and like x && y. This is evaluated as T.false(x) ? x : T.&(x, y).

Ok, so I have the following code. The struct contains an int and considers itself true if the int is greater than zero.:

public struct MyStruct {
    private int _i;

    public MyStruct(int i) {
        _i = i;
    }

    public static bool operator true(MyStruct ms) {
        return ms._i > 0;
    }

    public static bool operator false(MyStruct ms) {
        return ms._i <= 0;
    }

    public override string ToString() {
        return this._i.ToString();
    }
}

Now I would hope the following program will execute and use the overloaded false operator.

class Program {
    private static void Main() {
        MyStruct b1 = new MyStruct(1); // to be considered true
        MyStruct b2 = new MyStruct(-1); // to be considered false

        Console.WriteLine(b1 && b2);
        Console.WriteLine(b2 && b1);
    }
}

However, it does not even compile. It says it cannot apply operator '&&' to operands of type 'MyStruct' and 'MyStruct'.

I know I can implement an overload of the & operator. So let's do that. The & must return a MyStruct, so I can not make it return a bool.

public static MyStruct operator &(MyStruct lhs, MyStruct rhs) {
    return new MyStruct(lhs._i & rhs._i);
}

Now the code does compile. Its output is 1 and -1. So the result of b1 && b2 is not the same as that of b2 && b1.

If I debug the code, I see that b1 && b2 first executes the false operator on b1, which returns false. Then it performs the & operator on b1 and b2, which performs a bitwise and on 1 and -1, resulting in 1. So it indeed is first checking if b1 is false.

The second expression, b2 && b1 first executes the false operator on b2, which returns true. Combined with the fact I'm using short circuiting, it doesn't do anything with b1 and just prints out the value of b2.

So yes, the false operator is executed when you use short circuiting. However, it does not execute the true or false operator on the second argument, but instead executes the overloaded & operator on the operands.

When can this ever be useful? Or how can I make my type so that it can check if the two variables both are true?

like image 432
comecme Avatar asked Jun 26 '11 19:06

comecme


1 Answers

The contents of the URL you mentioned that was 404 can be found here:

http://web.archive.org/web/20080613013350/http://www.ayende.com/Blog/archive/2006/08/04/7381.aspx

The article that the author is referring to is here:

http://web.archive.org/web/20081120013852/http://steve.emxsoftware.com/NET/Overloading+the++and++operators

To avoid the same issue again, here is the highlights from the article:

A couple months ago I posted about our query API along with an explanation of how it works. Our query API allows us to express our queries using strongly typed C# syntax:

List<Customer> customers = repository.FindAll(Customer.Columns.Age == 20 & Customer.Columns.Name == “foo”);

One of the things I pointed out in my previous posts was that I couldn’t overload the && and || operators directly since the framework doesn’t allow such craziness…at least not directly.

In particular, it is not possible to overload member access, method invocation, or the =, &&, ||, ?:, checked, unchecked, new, typeof, as, and is operators. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/vclrfcsharpspec_7_2_2.asp

Over the last month I’ve done a little investigation on the topic to see if and how I can get && and || to behave the way I want. This evening I came across the Conditional logical operators page on MSDN which gave me the answer I was looking for:

The operation x && y is evaluated as T.false(x) ? x : T.&(x, y), where T.false(x) is an invocation of the operator false declared in T, and T.&(x, y) is an invocation of the selected operator &. In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Then, if x is definitely false, the result of the operation is the value previously computed for x. Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x and the value computed for y to produce the result of the operation. The operation x || y is evaluated as T.true(x) ? x : T.|(x, y), where T.true(x) is an invocation of the operator true declared in T, and T.|(x, y) is an invocation of the selected operator |. In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Then, if x is definitely true, the result of the operation is the value previously computed for x. Otherwise, y is evaluated, and the selected operator | is invoked on the value previously computed for x and the value computed for y to produce the result of the operation. Since we already have the & and | operators in place it was simply a matter of overloading the true and false operators to both return false. This results in the & and | operators always being called which in turn results in the two criteria objects being turned into an AndCriteria/OrCriteria!

So now we can express our criteria expressions using the && and || syntax we’re accustomed to.

repository.FindAll(Customer.Columns.Age == 20 && Customer.Columns.Name == “foo”);

repository.FindAll(Customer.Columns.FirstName == “Foo” || Customer.Columns.LastName == “Bar”);

The relevant operator overloads are shown below.

public static bool operator true(Criteria<T> criteria) {
   return false;
}

public static bool operator false(Criteria<T> criteria) {
   return false;
}

public static Criteria<T> operator &(Criteria<T> lhs, Criteria<T> rhs) {
   return new AndCriteria<T>(lhs, rhs);
}

public static Criteria<T> operator |(Criteria<T> lhs, Criteria<T> rhs) {
   return new OrCriteria<T>(lhs, rhs);
}
like image 135
IAmTimCorey Avatar answered Sep 20 '22 15:09

IAmTimCorey