473,385 Members | 1,542 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Shortcircuiting operators in C#

TB
This is a repost of something I had posted four months ago with no
response, I'm hoping to get some feedback...

From the Microsoft .net Core Reference (pg. 104)
C# shares the AND (short-circuit) operator (&&) with C and C++.
This operator works with two operands, evaluating as 'true' if
both operands are true.

But later (pg. 124)
Behind the scenes, the compiler combines the 'true', 'false',
and '&' operators in the following way to evaluate the &&
operator:

if (Foo.false(a) != true)
return Foo.true(Foo.operator & (a, b));
else
return Foo.true(a);

I have verified this by overriding the 'true', 'false', and '&'
operators
to display tracing information.

Now this raises a couple of issues in my mind...

1) This seems horribly inefficient. For example, if 'a', the left
hand
object, evaluates to false we end up determining it's boolean value
twice in
order to get our return value. The same is true of operator ||.
Wouldn't a much simpler, cleaner, and *more correct* way to do this
be:

&& ||
----------------- -----------------
if (Foo.false(a)) if (Foo.true(a))
return false; return true;
else else
return Foo.true(b); return Foo.true(b);

2) The short-circuit operator is *not* just a simple boolean operation
since it relies on the implementation of operator& (which returns a
new
object). It is possible for both 'a' and 'b' to separately evaluate
as
true but for 'a & b' to evaluate as false. Yes, yes, I know... this
is
probably a sign of a design mistake, but consider the following
example...

struct MyInt
{
private int _val;

public MyInt(int v) { _val = v; }
public Value
{
get { return _val; }
set { _val = value; }
}

static public bool operator true(MyInt a)
{
return a.Value != 0;
}

static public bool operator false(MyInt a)
{
return a.Value == 0;
}

static public MyInt operator &(MyInt a, MyInt b)
{
return new MyInt(a.Value & b.Value);
}
}

i.e. a pretty simple class that basically just encapsulates a single
int.
Now consider this...

MyInt a(7);
MyInt b(32);
if (a)
Console.WriteLine("a is true!"); // <== non-zero is true
else
Console.WriteLine("a is false!");

if (b)
Console.WriteLine("b is true!"); // <== non-zero is true
else
Console.WriteLine("b is false!");

if (a && b)
Console.WriteLine("a && b is true!");
else
Console.WriteLine("a && b is false!"); // (7 & 32) == 0

The C# method of using the bitwise-AND to implement the logical-AND
(short circuiting) leads to this confusing result.

Comments??

-- TB
Nov 15 '05 #1
6 2588
I agree that that is a very misleading description.

If you look at the C# language spec, section 7.11.1 discussions boolean
conditional operators. It says:

The operation x && y is evaluated as "x ? y: false". In other words, x is
first evaluated and converted to type bool. Then, if x is true, y is
evaluated and converted to type bool, and this becomes the result of the
operation. Otherwise, the result of the operation is false.

Similarly, x || y is evaluated as "x ? true: y"

This is pretty close to what you list at the end of section (1).

As for section (2), C# has this capability because there are nullable types
where a != b is not necessarily equal to !(a == b), because of the third
state (SqlBool is the canonical example of this). We support overloading
true and false so that you can get the right behavior for expressions with
these types, but unless you have that kind of type, you would never need to
overload true and false.

Hope that helps.
--
Eric Gunnerson

Visit the C# product team at http://www.csharp.net
Eric's blog is at http://blogs.gotdotnet.com/ericgu/

This posting is provided "AS IS" with no warranties, and confers no rights.
"TB" <tb*********@kaxy.com> wrote in message
news:cd**************************@posting.google.c om...
This is a repost of something I had posted four months ago with no
response, I'm hoping to get some feedback...

From the Microsoft .net Core Reference (pg. 104)
C# shares the AND (short-circuit) operator (&&) with C and C++.
This operator works with two operands, evaluating as 'true' if
both operands are true.

But later (pg. 124)
Behind the scenes, the compiler combines the 'true', 'false',
and '&' operators in the following way to evaluate the &&
operator:

if (Foo.false(a) != true)
return Foo.true(Foo.operator & (a, b));
else
return Foo.true(a);

I have verified this by overriding the 'true', 'false', and '&'
operators
to display tracing information.

Now this raises a couple of issues in my mind...

1) This seems horribly inefficient. For example, if 'a', the left
hand
object, evaluates to false we end up determining it's boolean value
twice in
order to get our return value. The same is true of operator ||.
Wouldn't a much simpler, cleaner, and *more correct* way to do this
be:

&& ||
----------------- -----------------
if (Foo.false(a)) if (Foo.true(a))
return false; return true;
else else
return Foo.true(b); return Foo.true(b);

2) The short-circuit operator is *not* just a simple boolean operation
since it relies on the implementation of operator& (which returns a
new
object). It is possible for both 'a' and 'b' to separately evaluate
as
true but for 'a & b' to evaluate as false. Yes, yes, I know... this
is
probably a sign of a design mistake, but consider the following
example...

struct MyInt
{
private int _val;

public MyInt(int v) { _val = v; }
public Value
{
get { return _val; }
set { _val = value; }
}

static public bool operator true(MyInt a)
{
return a.Value != 0;
}

static public bool operator false(MyInt a)
{
return a.Value == 0;
}

static public MyInt operator &(MyInt a, MyInt b)
{
return new MyInt(a.Value & b.Value);
}
}

i.e. a pretty simple class that basically just encapsulates a single
int.
Now consider this...

MyInt a(7);
MyInt b(32);
if (a)
Console.WriteLine("a is true!"); // <== non-zero is true
else
Console.WriteLine("a is false!");

if (b)
Console.WriteLine("b is true!"); // <== non-zero is true
else
Console.WriteLine("b is false!");

if (a && b)
Console.WriteLine("a && b is true!");
else
Console.WriteLine("a && b is false!"); // (7 & 32) == 0

The C# method of using the bitwise-AND to implement the logical-AND
(short circuiting) leads to this confusing result.

Comments??

-- TB

Nov 15 '05 #2
TB
"Eric Gunnerson [MS]" <er****@online.microsoft.com> wrote in message news:<#Q**************@TK2MSFTNGP12.phx.gbl>...
I agree that that is a very misleading description.

If you look at the C# language spec, section 7.11.1 discussions boolean
conditional operators. It says:

The operation x && y is evaluated as "x ? y: false". In other words, x is
first evaluated and converted to type bool. Then, if x is true, y is
evaluated and converted to type bool, and this becomes the result of the
operation. Otherwise, the result of the operation is false.

Similarly, x || y is evaluated as "x ? true: y"

This is pretty close to what you list at the end of section (1).
Hmmm... yes and no. The first part of section 7.11.1 (thanks, by the
way, for pointing this out -- I keep forgetting that the language
specification is there) says that, "when the operands are of types
that do not define an applicable operator & or operator |, but do
define implicit conversions to bool, the operation is processed as
follows:"

So this seems to depend on whether a given object has an implicit
'bool' conversion or not and whether the object defines the &, true,
and false operators. Again, consider the simple test struct:

struct IntWrapper
{
private int m_val;
public IntWrapper(int v) { m_val = v; }
public int Value { get {return m_val;} set {m_val = value;}}

static public bool operator true (IntWrapper iw) {
return iw.Value != 0; }

static public bool operator false (IntWrapper iw) {
return iw.Value == 0; }

static public IntWrapper operator & (IntWrapper a, IntWrapper b)
{
return new IntWrapper(a.Value & b.Value); }
}

The && operator for two IntWrappers goes through the following:
operator false(a)
operator &(a, b) ==> temp
operator true(temp)

Now add the following implicit conversion without changing anything
else:

static public implicit operator bool(IntWrapper iw) {
return iw.Value != 0; }

Performing a && b now yields this slightly different sequence:
operator false(a)
operator &(a, b) ==> temp
operator bool(temp)

Finally, remove our operator true(), operator false(), and operator
&() to get the sequence you describe (as well as a "correct" result):
operator bool(a)
operator bool(b)

One note, it appears that one cannot provide an operator &() without
the corresponding operator true() and operator false() (compiler
error). So it is impossible to tell whether such an operator would
still be invoked in the process of evaluating operator &&().

As for section (2), C# has this capability because there are nullable types
where a != b is not necessarily equal to !(a == b), because of the third
state (SqlBool is the canonical example of this). We support overloading
true and false so that you can get the right behavior for expressions with
these types, but unless you have that kind of type, you would never need to
overload true and false.
Hmmm... I know about nullable types (null being neither true nor
false), but at least for SqlBoolean I cannot think of a single case
where (a != b) is not the same as !(a == b). Granted, the == and !=
operators can return SqlBoolean.Null if either (or both) operands are
SqlBoolean.Null, but the two results are the same.

However, I'll grant that there may well be types where (a != b) is not
logically equivalent to !(a == b) even though I cannot think of any
examples of this offhand :-)

Hope that helps.


Yes, if nothing else, it helps point out that operator overloading is
still a potentially hairy thing to do (as it is in C++) and should be
done carefully. Thanks for the feedback!

-- TB
Nov 15 '05 #3
you want to claim that
if (Foo.false(a) != true)
return Foo.true(Foo.operator & (a, b));
else
return Foo.true(a);

is not as efficient as
&&
-----------------
if (Foo.false(a))
return false;
else
return Foo.true(b);
But the first statement can accomplish its goals with evaluation of one part
of the if-else clauses. Where as your implementation would cause both
clauses to fire off many times.

"TB" <tb*********@kaxy.com> wrote in message
news:cd**************************@posting.google.c om... This is a repost of something I had posted four months ago with no
response, I'm hoping to get some feedback...

From the Microsoft .net Core Reference (pg. 104)
C# shares the AND (short-circuit) operator (&&) with C and C++.
This operator works with two operands, evaluating as 'true' if
both operands are true.

But later (pg. 124)
Behind the scenes, the compiler combines the 'true', 'false',
and '&' operators in the following way to evaluate the &&
operator:

if (Foo.false(a) != true)
return Foo.true(Foo.operator & (a, b));
else
return Foo.true(a);

I have verified this by overriding the 'true', 'false', and '&'
operators
to display tracing information.

Now this raises a couple of issues in my mind...

1) This seems horribly inefficient. For example, if 'a', the left
hand
object, evaluates to false we end up determining it's boolean value
twice in
order to get our return value. The same is true of operator ||.
Wouldn't a much simpler, cleaner, and *more correct* way to do this
be:

&& ||
----------------- -----------------
if (Foo.false(a)) if (Foo.true(a))
return false; return true;
else else
return Foo.true(b); return Foo.true(b);

2) The short-circuit operator is *not* just a simple boolean operation
since it relies on the implementation of operator& (which returns a
new
object). It is possible for both 'a' and 'b' to separately evaluate
as
true but for 'a & b' to evaluate as false. Yes, yes, I know... this
is
probably a sign of a design mistake, but consider the following
example...

struct MyInt
{
private int _val;

public MyInt(int v) { _val = v; }
public Value
{
get { return _val; }
set { _val = value; }
}

static public bool operator true(MyInt a)
{
return a.Value != 0;
}

static public bool operator false(MyInt a)
{
return a.Value == 0;
}

static public MyInt operator &(MyInt a, MyInt b)
{
return new MyInt(a.Value & b.Value);
}
}

i.e. a pretty simple class that basically just encapsulates a single
int.
Now consider this...

MyInt a(7);
MyInt b(32);
if (a)
Console.WriteLine("a is true!"); // <== non-zero is true
else
Console.WriteLine("a is false!");

if (b)
Console.WriteLine("b is true!"); // <== non-zero is true
else
Console.WriteLine("b is false!");

if (a && b)
Console.WriteLine("a && b is true!");
else
Console.WriteLine("a && b is false!"); // (7 & 32) == 0

The C# method of using the bitwise-AND to implement the logical-AND
(short circuiting) leads to this confusing result.

Comments??

-- TB

Nov 15 '05 #4


--
Eric Gunnerson

Visit the C# product team at http://www.csharp.net
Eric's blog is at http://blogs.gotdotnet.com/ericgu/

This posting is provided "AS IS" with no warranties, and confers no rights.
"TB" <tb*********@kaxy.com> wrote in message
news:cd**************************@posting.google.c om...
"Eric Gunnerson [MS]" <er****@online.microsoft.com> wrote in message news:<#Q**************@TK2MSFTNGP12.phx.gbl>...
I agree that that is a very misleading description.

If you look at the C# language spec, section 7.11.1 discussions boolean
conditional operators. It says:

The operation x && y is evaluated as "x ? y: false". In other words, x is first evaluated and converted to type bool. Then, if x is true, y is
evaluated and converted to type bool, and this becomes the result of the
operation. Otherwise, the result of the operation is false.

Similarly, x || y is evaluated as "x ? true: y"

This is pretty close to what you list at the end of section (1).


Hmmm... yes and no. The first part of section 7.11.1 (thanks, by the
way, for pointing this out -- I keep forgetting that the language
specification is there) says that, "when the operands are of types
that do not define an applicable operator & or operator |, but do
define implicit conversions to bool, the operation is processed as
follows:"

So this seems to depend on whether a given object has an implicit
'bool' conversion or not and whether the object defines the &, true,
and false operators. Again, consider the simple test struct:

struct IntWrapper
{
private int m_val;
public IntWrapper(int v) { m_val = v; }
public int Value { get {return m_val;} set {m_val = value;}}

static public bool operator true (IntWrapper iw) {
return iw.Value != 0; }

static public bool operator false (IntWrapper iw) {
return iw.Value == 0; }

static public IntWrapper operator & (IntWrapper a, IntWrapper b)
{
return new IntWrapper(a.Value & b.Value); }
}

The && operator for two IntWrappers goes through the following:
operator false(a)
operator &(a, b) ==> temp
operator true(temp)

Now add the following implicit conversion without changing anything
else:

static public implicit operator bool(IntWrapper iw) {
return iw.Value != 0; }

Performing a && b now yields this slightly different sequence:
operator false(a)
operator &(a, b) ==> temp
operator bool(temp)

Finally, remove our operator true(), operator false(), and operator
&() to get the sequence you describe (as well as a "correct" result):
operator bool(a)
operator bool(b)

One note, it appears that one cannot provide an operator &() without
the corresponding operator true() and operator false() (compiler
error). So it is impossible to tell whether such an operator would
still be invoked in the process of evaluating operator &&().

As for section (2), C# has this capability because there are nullable types where a != b is not necessarily equal to !(a == b), because of the third
state (SqlBool is the canonical example of this). We support overloading
true and false so that you can get the right behavior for expressions with these types, but unless you have that kind of type, you would never need to overload true and false.


Hmmm... I know about nullable types (null being neither true nor
false), but at least for SqlBoolean I cannot think of a single case
where (a != b) is not the same as !(a == b). Granted, the == and !=
operators can return SqlBoolean.Null if either (or both) operands are
SqlBoolean.Null, but the two results are the same.

However, I'll grant that there may well be types where (a != b) is not
logically equivalent to !(a == b) even though I cannot think of any
examples of this offhand :-)


IIRC, with SqlBoolean, null is neither equal nor not equal to other values.
I could be wrong, however.


Hope that helps.


Yes, if nothing else, it helps point out that operator overloading is
still a potentially hairy thing to do (as it is in C++) and should be
done carefully. Thanks for the feedback!

-- TB

Nov 15 '05 #5
TB
"john bailo" <jb****@vestcom.com> wrote in message news:<8d******************************@news.terane ws.com>...
you want to claim that
if (Foo.false(a) != true)
return Foo.true(Foo.operator & (a, b));
else
return Foo.true(a);


is not as efficient as
&&
-----------------
if (Foo.false(a))
return false;
else
return Foo.true(b);


But the first statement can accomplish its goals with evaluation of one part
of the if-else clauses. Where as your implementation would cause both
clauses to fire off many times.


I'm not sure I see your point. Whether the else-clause is evaluated
or not depends solely on the boolean value for 'a' in both cases
(albeit expressed slightly differently). In the first implementation
the evaluation of 'b' is short-circuited if the else-clause is taken.
In the second implementation the evaluation of 'b' is short-circuited
if the if-clause is taken.

In the first implementation, however, the body of the if-clause
constructs a brand-new, temporary object via operator&() and then
evaluates its boolean value for the final result. Does this not seem
like it would generally be less efficient than the second
implementation?

-- TB
Nov 15 '05 #6
TB
"Eric Gunnerson [MS]" <er****@online.microsoft.com> wrote in message news:<OD**************@tk2msftngp13.phx.gbl>...
This posting is provided "AS IS" with no warranties, and confers no rights.
"TB" <tb*********@kaxy.com> wrote in message
news:cd**************************@posting.google.c om...
"Eric Gunnerson [MS]" <er****@online.microsoft.com> wrote in message

news:<#Q**************@TK2MSFTNGP12.phx.gbl>...
As for section (2), C# has this capability because there are nullable types where a != b is not necessarily equal to !(a == b), because of the third
state (SqlBool is the canonical example of this). We support overloading
true and false so that you can get the right behavior for expressions with these types, but unless you have that kind of type, you would never need to overload true and false.


Hmmm... I know about nullable types (null being neither true nor
false), but at least for SqlBoolean I cannot think of a single case
where (a != b) is not the same as !(a == b). Granted, the == and !=
operators can return SqlBoolean.Null if either (or both) operands are
SqlBoolean.Null, but the two results are the same.

However, I'll grant that there may well be types where (a != b) is not
logically equivalent to !(a == b) even though I cannot think of any
examples of this offhand :-)


IIRC, with SqlBoolean, null is neither equal nor not equal to other values.
I could be wrong, however.


True, but nonetheless all cases of (a != b) vs !(a == b) where a and b
are various values for SqlBoolean yield identical results.

-- TB
Nov 15 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: greg | last post by:
Discussion is invited on the following proto-PEP. ------------------------------------------------------------- PEP ??? - Overloadable Boolean Operators...
4
by: GianGuz | last post by:
Global new and delete operators can be overloaded to suite particulars needs. Typically they are overloaded to insert useful debugging/trace informations. What I would to discuss here concerns the...
6
by: bearophileHUGS | last post by:
Sometimes I suggest to add things to the language (like adding some set methods to dicts), but I've seen that I tend to forget the meaning of six set/frozenset operators: s & t s &= t s | t s...
6
by: jas_lx | last post by:
The basic understanding of what bitwise operators (& ^ | >> << ) comes fairly simple, as long as one has a fundamental understanding of bits, bytes and binary. Having done some Win32...
2
by: Steve Summit | last post by:
-----BEGIN PGP SIGNED MESSAGE----- It's often explained that the reason for some of the imprecision in C's definition is so that C can be implemented on different kinds of machines -- say, those...
49
by: raju | last post by:
hi can we compare two integers without using relational operators (== != < <= > >=) thanks rajesh s
0
by: Syanide | last post by:
here's a bit info for you fellas: eg.. you have Square classes u wanna add public static int operator+ (Square s1, Square s2) { // your code here } comparision operators..
17
by: Steve R. Hastings | last post by:
I have been studying Python recently, and I read a comment on one web page that said something like "the people using Python for heavy math really wish they could define their own operators". The...
28
by: dspfun | last post by:
I'm trying to get a good understanding of how unary operators work and have some questions about the following test snippets. int *p; ~!&*++p--; It doesn't compile, why? The problem seems to be...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.