7

Following this very interesting issue which was originated from this question -

I want to take 1 steps back please (removed the dynamic environment) :

Looking at this code : ( a variant of this one)

void Main()
{
    int a;
     int b = 100;
    Console.WriteLine(X.M(1, out a));

}

public class X
{
    public  int H=0;

    public static X M(int x, out int y)
    {
        Console.WriteLine("x = "+x);
        y = x;
        return new X(x);
    }

    public X(){}

    public X(int h)
    {
        H=h;
    }

    public static bool operator false(X x)     {Console.WriteLine("in false operator for "+ x.H); return true; }
    public static bool operator true(X x)      {Console.WriteLine("in true operator for "+ x.H); return true; }
    public static X operator &(X a, X b)       {Console.WriteLine("in & operator for "+ a.H+","+b.H);   return new X(); }
    public static implicit operator bool (X x) {Console.WriteLine("in bool operator for "+ x.H);return true; }
}

The result is :

x = 1
in bool operator for 1
True

This is understood :

  • The x = 1 is from the method itself ( using Console.Writeline)
  • in bool operator for 1 is from the implicit operator from X to Bool (so - Console.WriteLine treats the whole expression as Console.Writeline(bool))
  • The last "True" is from the "return true" in the operator bool (X x)

OK - So let's change

Console.WriteLine(X.M(1, out a));

to

Console.WriteLine(X.M(1, out a) &&  X.M(2, out b));

Now - the result is :

x = 1
in false operator for 1
in bool operator for 1
True

2 questions :

  1. Why does this in false operator for 1 executes ? I don't see any reason for false to be present here.

  2. I could understand why the right part in X.M(1, out a) && X.M(2, out b) won't executes ONLY if the left part is false - but again I don't see how the left part can be false. It does return true (according to my first code)

NB

I've read many times the answers from the post :

Jon said :

The second && is a normal && between two bool expressions - because Nop returns bool, and there's no &(X, bool) operator... but there is a conversion from X to bool.

So it's more like:

bool first = X.M(1, out a) && X.M(2, out b);
if (first && Nop(a, b))

Now first is true even though only the first operand of && has been evaluated... so b really hasn't been assigned.

Still I don't understand : "first is true(????) even though only the first operand of && has been evaluated"

Community
  • 1
  • 1
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • If the `false()` operator returns `true` then it means that the operation returns `false` ("is x false? yes it is (return true;)")! It isn't an `operator bool()`. – xanatos Aug 14 '15 at 11:47
  • The `false()` operator is called to short-circuit the `&&`... They could have called the `true()` operator, but for example the definition of `&&` in [msdn](https://msdn.microsoft.com/en-us/library/2a723cdk.aspx): *except that **if x is false**, y is not evaluated* – xanatos Aug 14 '15 at 11:49
  • See http://stackoverflow.com/a/5203515/613130 : *&& is defined as a short-circuiting operator; **if the first operand evaluates false**, it is demanded to short circuit there and not evaluate the right hand side.* – xanatos Aug 14 '15 at 11:51
  • @xanatos Yes. but that'st the problem I dont see where the first operand gets to have a false value. – Royi Namir Aug 14 '15 at 11:52
  • You `return true;` in `operator false(X x)` (`{Console.WriteLine("in false operator for "+ x.H); **return true;** }`). Try changin it to `return false;` – xanatos Aug 14 '15 at 11:53
  • @xanatos Sorry , I might be nagging but why does the control gets into `operator false(X x) ` at first place ??? – Royi Namir Aug 14 '15 at 11:54
  • 1
    Because the `&&` operator is translated to if (not operator false(left expression)) then calculate right expression – xanatos Aug 14 '15 at 11:55

1 Answers1

5

Firstly, don't forget that this is deliberately bizarre code, used to find a corner case. If you ever find a type that behaves like this in a genuine program, find the author and have a quiet word with them.

Still I don't understand : "first is true(????) even though only the first operand of && has been evaluated"

Yes, because of the way the && operand is handled in the case where the operands aren't bool. It's specified in section 7.12.2 of the C# spec:

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 &. 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.

So, in order:

  • X.M(1, out a) is invoked, to get a result - call it op1 for the moment
  • Next X.false(op1) is invoked, and returns true
  • Then by the above, the result of the expression X.M(1, out a) && X.M(2, out b) is op1
  • Next, the value of the conversion from op1 to bool is invoked, and that returns true. This is due to overload resolution for Console.WriteLine.

To answer your specific confusion:

but again I don't see how the left part can be false.It does return true (according to my first code)

It returns a value which is somewhat contradictory - it's false in that the false operator returns true, but it's true in that the conversion to bool returns true. Once you understand that it's the value returned by the false operator which determines whether or not to evaluate the second operand of &&, it should all be clear.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • But why does it invoke ```operator bool```? As I interpret the spec, the result of the ```&&``` operation should just be the result of the ```operator &``` call. – erikkallen Aug 14 '15 at 12:32
  • 1
    @erikkallen: This depends on the context :) In the context of the `Console.WriteLine` call, it's because there's an overload accepting `bool`, and that's more specific than the overload accepting `object`. In the original context of Neal Gafter's program, it was because the result was going to be used as the first operand in *another* `&&` expression, where the right hand expression was of type `bool`. – Jon Skeet Aug 14 '15 at 12:38
  • Thank you for the explanation. I must say that I am rather surprised that it will use implicit operators to locate more specific overloads. – erikkallen Aug 14 '15 at 13:04