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 :
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)
)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 :
Why does this in false operator for 1
executes ? I don't see any reason for false
to be present here.
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"
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 asT.false(x) ? x : T.&(x, y)
whereT.false(x)
is an invocation of theoperator false
declared inT
, andT.&(x, y)
is an invocation of the selected operator in&
. In other words,x
is first evaluated andoperator false
is invoked on the result to determine ifx
is definitely false. Then, ifx
is definitely false, the result of the operation is the value previously computed forx
. Otherwise,y
is evaluated, and the selectedoperator &
is invoked on the value previously computed forx
and the value computed fory
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 momentX.false(op1)
is invoked, and returns true
X.M(1, out a) && X.M(2, out b)
is op1
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.
See more on this question at Stackoverflow