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"

7
  • 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(). Commented Aug 14, 2015 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: except that if x is false, y is not evaluated Commented Aug 14, 2015 at 11:49
  • See 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. Commented Aug 14, 2015 at 11:51
  • @xanatos Yes. but that'st the problem I dont see where the first operand gets to have a false value. Commented Aug 14, 2015 at 11:52
  • 1
    Because the && operator is translated to if (not operator false(left expression)) then calculate right expression Commented Aug 14, 2015 at 11:55

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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: 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.
Thank you for the explanation. I must say that I am rather surprised that it will use implicit operators to locate more specific overloads.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.