14

I got frustated with my other question. So i wrote up this example.

In C the below is true. See demo

int main()
{
printf("%d", 1 && 2);
return 0;
}

Output:

1

In C#. It is FALSE. WHY is this false? Also i dont understand why i needed to create the bool operator in this example but not the one in my other question but no matter. Why is the below false? it makes no sense to me.

BTW the logic making the below false is described here

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyInt a=1, b=2;
            bool res=a && b;
            Console.WriteLine("result is {0}", res);
        }

        class MyInt
        {
            public int val;
            public static bool operator true(MyInt t) { return t.val != 0; }
            public static bool operator false(MyInt t) { return t.val == 0; }
            public static MyInt operator &(MyInt l, MyInt r) { return l.val & r.val; }
            public static MyInt operator |(MyInt l, MyInt r) { return l.val | r.val; }
            public static implicit operator MyInt(int v) { return new MyInt() { val = v }; }
            public static implicit operator bool(MyInt t) { return t.val != 0; }
        }
    }
}
Community
  • 1
  • 1
  • 12
    If you want to code in C, code in C. If you want to code in C++, code in C++. If you want to code in C# code in C#. But you can't assume that these languages are interchangeable. You will have the most success if your code according to the rules of the language you are writing rather than coding to the rules of some other language. – David Heffernan Mar 05 '11 at 12:48
  • 4
    common convention should always trump every other aspect - if 1 has always been true, and 0 always been false, a language that does things differently should be criticised for it. Us poor humans only remember so much and we make mistakes, so changing conventions just makes mistakes more likely. – gbjbaanb Mar 05 '11 at 14:39
  • 2
    @gbjbaanb: Exactly and if its going to change at least tell us the reasoning behind it so we can take advantage of why it changed. Which is what i was trying to ask (three times. Almost no one got it). This (the why reason) is why i liked CodeInChaos answer in another question http://stackoverflow.com/questions/5203498/why-does-c-and-operators-work-the-way-they-do/5203892#5203892 –  Mar 05 '11 at 14:43
  • @gbjbaanb: 0 remains false and 1 remains true for the MyInt class above if the & and | operators are implemented correctly, as I specify below. The language doesn't "do things differently," at least not in the way you seem to imply. It just uses & and | as non-short-circuiting Boolean operators when the operands aren't integers. – Jollymorphic Mar 05 '11 at 18:52
  • @gbjbaanb: 1 has not always been true in all languages... sometimes -1 has been, e.g. in VB (all bits set to 1 in an int). – Eric J. Mar 06 '11 at 17:38
  • @acidzombie24: When you pick up a new language, suggest you read through the language specification first. I'm not trying to be negative... this is a serious suggestion. Languages evolve over time and it's important to understand the difference between what you already know and what you are learning. – Eric J. Mar 06 '11 at 17:40
  • 1
    @Eric J.: I read generics, getters, setters, this[T t], how explicit/implicit cast work since it was different from C++ operator T(). However, i did not look at how for loops work or how '|' works since every language has them and they all work the same. However, i did not think || would be different nor seen it different up until now. And its done a good job making me believe its the same. I dont suppose you suggest i should read up on how function call work in every language? (but i do know named parameters but that was new since the version i started with) Or the assignment operator? –  Mar 06 '11 at 17:52
  • I looked at their C++ to C# guide before any of that. This was NOT one of the things in that document. I dont know if you take that suggest back now but w/e. One funny thing about the assignment operator being the same in every language. They works differently in my language. It obvious though. –  Mar 06 '11 at 17:55

4 Answers4

22

In C there is no bool. Convention is that 0 is false and != 0 is true. if statement treated conditional expression result exactly that way.

In C++ bool was introduced. But it was compatible with old rules, 0 treated as false and false as 0, and there was implicit conversion between int and bool.

In C# it is not the same way: there is bool and int and they are not convertible to eachother. That is what C# Standard says. Period.

So when you tried to reimplement bool and int compatibility you made a mistake. You use && which is logical operator, but in C# you can't override it and only &, which is implemented as bitwise. 1 & 2 == 0 == false! here it is!

You even should not overload bitwise ones, to maintain compatibility you just have to leave operator true and false.

This code works as you expect:

class Programx
{
    static void Main(string[] args)
    {
        MyInt a = 1, b = 2;
        bool res = a && b;
        Console.WriteLine("result is {0}", res);
    }

    class MyInt
    {
        public int val;
        public static bool operator true(MyInt t)
        {
            return t.val != 0;
        }
        public static bool operator false(MyInt t)
        {
            return t.val == 0;
        }
        public static implicit operator MyInt(int v)
        {
            return new MyInt() { val = v };
        }
        public static implicit operator bool(MyInt t)
        {
            return t.val != 0;
        }
    }
}

result is True

Andrey
  • 56,384
  • 10
  • 111
  • 154
  • I always assumed int was not implicitly cast to bool to avoid accidental if/while/for problems. If i wrote this the result is true var b1 = Convert.ToBoolean(a.val); var b2 = Convert.ToBoolean(b.val); Console.WriteLine("result is {0}", b1&&b2);. Why doesnt C# do boolean AND the way C does. Why is the boolean and logic the way it is? –  Mar 05 '11 at 12:28
  • 2
    In C there *was* no `bool` until 1999. – Mike Seymour Mar 05 '11 at 12:31
  • Ok accepted as the answer. But... WTF, now i cant use bitwise ands. And if i do add bitwise ands logical ands break... WTF. I still dont understand why C# uses && as a short circuit &. –  Mar 05 '11 at 12:49
  • using logical operators on integers doesn't really make sense @acid. It's just a work around for c's weak type system. – CodesInChaos Mar 05 '11 at 12:56
  • @acidzombie24 let me try to explain in short words. C# compiler sees `x && y`, and neither of them are bools, your case. It checks is `operator false` defined. If it is there it is called. If it returns `false` expression value is false (short circuiting) if it returns `true` (your case) then `operator &` is called. But it returns bitwise, not logical result. This is the contradiction. – Andrey Mar 05 '11 at 13:07
  • @acidzombie24 root problem is that you mixed too much sorts of operations in one type. another thing is that C is weakly typed about bools and you are trying to loose strict C# typing to weak. – Andrey Mar 05 '11 at 13:08
  • @Mike the bool type in C is in the language called `_Bool`, not `bool`. The latte is merely a library macro. – Johannes Schaub - litb Mar 05 '11 at 13:14
  • @Andrey: For completeness i'll add in this answer which puts things in perspective. http://stackoverflow.com/questions/5203498/why-does-c-and-operators-work-the-way-they-do/5203892#5203892 –  Mar 05 '11 at 13:21
  • @acidzombie24 that answer is great – Andrey Mar 05 '11 at 13:25
  • @CodeInChaos: The behavior c uses for integers in Boolean context is perfectly reasonable in context. A great many (most, I believe) processors of that era had conditional branches like "jump-if-zero" and "jump-if-not-zero", and K&R were intimately familiar with assembly programming in that environment. Imposing a strongly differentiated `bool` type would have been silly for a systems programming language targeting those processors. – dmckee --- ex-moderator kitten Mar 05 '11 at 13:53
  • 1
    Even today processors work with these instructions. The abstraction of having a bool different from int doesn't cost any performance, but makes the language cleaner. Just like there is no difference between a pointer and an integer as far as the processor is concerned. But it still makes sense to separate those in a language. It's the usual case that if you are too familiar with something you are blind to alternatives, even if the alternative is better. Unfortunately that happens to all of us more often than we'd like. – CodesInChaos Mar 05 '11 at 14:01
  • @Andrey: You hit the nail on the head saying that the attempt to implement "bool and int compatibility" was a mistake, but I disagree with your followup. Specifically, when you assert that the & operator, when overridden on a class type, is "implemented as bitwise." It's "implemented as" a non-short-circuiting logical AND operator on class types that are advertising the fact that they want to be treated like Boolean types (by participating in logical & and && expressions). "1 & 2 == 0 == false" is a non-sequitor, because the zero and the false have no relationship to one another in C#. – Jollymorphic Mar 05 '11 at 19:02
  • @CodeInChaos: In 1972 asking a programmer to give up cycles to preserve an abstraction was *dumb*. All the more so in a language that was designed to implement much of the core functionality of a OS running on a simple (for that era!) machine. Simple compilers, machine memories measured in kilowords and speeds in thousands of operations per second: machine time cost more than programmer time which is very different from the world we live in. – dmckee --- ex-moderator kitten Mar 05 '11 at 19:24
  • 1
    You're not giving up any cycles at runtime. And the pascal compilers of the same era had that exact feature – CodesInChaos Mar 05 '11 at 19:31
  • @dmckee: I wonder if there are/were any machines where having `a && b` and `a || b` always return 1 if the result is non-zero would be faster than having it return the value of `a` in the early-exit case and the value of `b` otherwise? I know of many machines where the latter semantics would have been faster in addition to being in many cases more helpful. – supercat Aug 09 '13 at 20:17
9

Your implementations of operator& and operator| are wrong. These binary operators have bitwise meanings when applied to integral types, and when applied to either Boolean types or classes that have their own & and | operators, they have logical AND and OR semantics (being the non-short-circuiting cousins of && and ||). Correct implementations would look as follows:

operator &(MyInt l, MyInt r) {return l.val != 0 && r.val != 0);}
operator |(MyInt l, MyInt r) {return l.val != 0 || r.val != 0);}
Jollymorphic
  • 3,460
  • 14
  • 16
  • WTF!?! So... & is either logical or short circuited logical? not Boolean logical? (maybe i am saying this wrong but i think you know what i mean?) –  Mar 05 '11 at 12:30
  • And the bottom line is you simply cannot make an integer type in C# that supports bitwise operations to that integer with the & and | operator and at the same time overload true/false to provide a logical truth test. – nos Mar 05 '11 at 12:30
  • Why on earth would it be like this!?!?! –  Mar 05 '11 at 12:30
  • 2
    @acidzombie24: I'm afraid I don't get what you mean by the distinction. & and |, when supported as user-defined operators on a class, do double duty supporting both the non-short-circuiting logical (i.e., Boolean) & and | operations and the short-circuiting logical (i.e., Boolean) && and || operations. They are not intended to support bitwise (i.e., binary mathematical) operations. – Jollymorphic Mar 05 '11 at 12:34
  • it is plainly incorrect, because you are mixing bitwise and logical operators – Andrey Mar 05 '11 at 12:38
  • @Andrey: Exactly. I always thought && was boolean/logical and & was bitwise. But now i find out that && is a short circuit bitwise. What sense does that make!?! –  Mar 05 '11 at 12:44
  • 4
    @acid && isn't a short circuit bitwise on any reasonable type. The core of your problem is the misunderstanding that `&` means bitwise `and` in C#. It doesn't. It means non short-circuiting `and`. – CodesInChaos Mar 05 '11 at 12:48
  • 1
    And the problem with your type isn't the incorrect implementation of `&` it is the incorrect implementation of `true` and `false`. Those operators should not exist on a non logical type. See my answer to your old question on why these operators are designed like this in C#. – CodesInChaos Mar 05 '11 at 12:49
2

I'll try and make this simple, since I think people are overcomplicating this.

var x = 1 & 2;
// behind the scenes: 0001 AND 0010 = 0000
Console.Write(x); // 0, as shown above

Integers can NOT be used as booleans in C#. The result of:

if (1 && 2) // compile error
var x = 1 && 2; // compile error

There is no point to asking why an Integer can not be used as a boolean in C#, it just can't. The type system does not allow it. If one were to implement their own Integer class, they could provide implicit conversions from their type to bool, but int does not do this. You also have to make a choice when overloading; do you want bitwise behaviour, or logical behaviour. You can not have both.

Some languages allow 0, "", [] as 'falsey' values. C# does not. Get over it, and use a bool if you're doing boolean logic. If all else fails, Convert.ToBoolean on an int will return true for all non-zero values.

Josh Smeaton
  • 43,953
  • 24
  • 121
  • 160
1
public static MyInt operator &(MyInt l, MyInt r) { return l.val & r.val; }

If I read the linked article correctly, res = a && b will be "expanded" to:

MyInt.false(a) ? a : MyInt.&(a, b)

MyInt.false(a) is false, so evaluates to:

MyInt.&(a, b)

which "expands" to:

a.val & b.val

which is (1 & 2) == 0, and thus false.

Mat
  • 188,820
  • 38
  • 367
  • 383
  • Yes i knew that since the beginning thus why i asked my other question. My question is WHY ON EARTH is it doing this!?! –  Mar 05 '11 at 12:34
  • What part is annoying you? (1&2) == 0? – Mat Mar 05 '11 at 12:36
  • 2
    @acidzombie24 Why not? Imagine you come to C/C++ from Pascal do you start with: #define Begin { #define End } ? Or you'll read language reference and use new rules? – Nick Martyshchenko Mar 05 '11 at 12:36
  • @Mat: The fact that bool 1 is true and bool 2 is true but 1&&2 is not. –  Mar 05 '11 at 12:38
  • @Nick: Well, if && is logical and not boolean then why even bother to short circuit it? and if its suppose to be like C (since much of the syntax is similar) why even have the && or make it not boolean like C does. I dont understand its use if its suppose to do a logical and. –  Mar 05 '11 at 12:40
  • It's very useful, both for efficiency (not evaluating the right side if you don't need to) and to avoid NullPointerExceptions eg `if (o!=null && o.Property)` avoids horrible nested ifs and prevents an exception if it were just `if (o.Property)` when o was null – TimCodes.NET Mar 05 '11 at 12:52
  • If you want the C semantics so much, use C :-) C doesn't have operator overloading, so that simplifies the problem a lot from a language perspective. If you go with C++ for the expressivity and user-defined types, you'll be able to overload operator&&, but you'll loose short-circuiting in the process and that has some _surprising_ effects if you're not really really careful. It's always a matter of compromise. At least the behavior in C# preserves short-circuiting and is well documented. – Mat Mar 05 '11 at 13:08
  • @acidzombie24 I don't know what to add to other good explanations here. I'm really wonder why you with C++ background ask that :( I come to C# with ASM/C/C++ background and just keep in mind that Minimal / Short-circuit evaluation - http://en.wikipedia.org/wiki/Minimal_evaluation here. Have you read this article? Have you read http://stackoverflow.com/questions/1799072/c-short-circuiting-of-booleans ? – Nick Martyshchenko Mar 05 '11 at 13:11
  • @Nick: None of these answers are great IMO. This answer put things into perspective. http://stackoverflow.com/questions/5203498/why-does-c-and-operators-work-the-way-they-do/5203892#5203892 I come from asm as well and to me & means if left and right are set, the result is set. So i assume if left and right as a bool is true it would be true. I had no idea && wasnt a logical/boolean op in C#. This answer linked told me that and why it uses &. –  Mar 05 '11 at 13:24
  • @acidzombie24 C# is new language and it not C/C++. Yes, it utilizes some (or you can say "much") of С/С++ syntax and even semantics for easier migration for us. Yes, sometimes it can really confusing with different background, one of this is finalizer syntax (~) and have really confusing meaning in С++ (destructor) and C# (finalizer). Yes, there are many other language features, sometimes similar to other (C++, JAVA or even Delphi), sometimes differ. – Nick Martyshchenko Mar 05 '11 at 15:01
  • @acidzombie24 When I have to use new language (F#, Python, Haskell, Erlang or other, such as LISP, Prolog) in my work or just for studying I try do not implicate my previous language knowledge and start from reference. There are maybe academic interest why language designed in such way but not in another but when you start to use it you use it as it is, you can't really change language. You can stay in language of your choice without moving or construct another language and try to make it popular. – Nick Martyshchenko Mar 05 '11 at 15:02
  • @Nick: Really, the confusion was if it worked that way why bother having both && and &? If its data you'll want to always apply & and if its bool maybe you can specialize it and only short circuit there. CodingInChaos mention thats how pascal does it. Anyways my frustration was NO ONE said WHY it worked this way (except one) and told me i was 'doing it wrong' and told me to do it some other way with no reasoning why that other way works except that it 'works'. –  Mar 05 '11 at 16:55