10/13/2008

10-13-08 - 3

"bool" in C++ fucking sucks. For one thing, its size is undefined, so you can't ever store it, and yet tons of people do, which makes huge bugs if you ever switch compilers and the size of bool changes. (that "size of bool is undefined" was a stroke of genius by the standards committee, assuming their goal was to cause maximum heart damage). Another problem is that it silently converts into "int" which is pointless and evil so far as I can tell. The last big problem is that if you're trying to make code that works in C++ and C there appears to be no good way to set up a "bool-alike" that works in C.

I want a fricking thing that is either on or off, and can only be converted between ints with an actual boolean operation, like

int x = b ? 1:0;

or

bool b = (x >= 3);

If I was only in C++ I could fix the size thing. The best way to do it is to make your own class bool, like :


class Bool
{
public:
	Bool( bool b ) : m_val(b) { }
	
	operator bool () { return m_val ? true : false; }
	
private:
	S32 m_val;
};

which makes you act like bool but gaurantees a fixed size. But you can't integrate that with C.

To integrate with C I see only two options, either typedef Bool to an int, or typedef Bool to an enum. The enum is different but not really much better; enums still silently convert to int, but at least it does prevent int conversion to bool, but then it also doesn't convert actual booleans to the enum.

Example of bool horribleness :


enum EBool
{
	eFalse,eTrue
};

void testb(bool x,int y);
void testi(int x,int y);
void teste(EBool x,int y);

static void test()
{
	testb(true,3); // good
	testi(true,3); // silently bad
	teste(true,3); // error

	testb(4,7); // warning
	testb(1,7); // silently bad
	testi(4,7); // good
	teste(4,7); // error

	testb(eTrue,3); // silently bad
	testi(eTrue,3); // silently bad
	teste(eTrue,3); // good
}

It's easy enough to say "don't use bool" but I don't see a way around it. Obviously I could not ever store bools in structs (though that's hard to enforce and just leads to evil things like BOOL). The worse situation is function args like in our example above. I want to be able to make a function that takes a bool arg, and actually *requires* the client to pass in either "true" or "false", not some random int (or 0 or 1). In particular, when I change a function signature, I want compile errors when people call with the old signature.

In C++ I can do this :


class Bool
{
public:
	explicit Bool( bool b ) : m_val(b) { }
	
	static const Bool T;
	static const Bool F;
		
	bool operator == ( const Bool & b ) const { return m_val == b.m_val; }
	bool operator != ( const Bool & b ) const { return m_val != b.m_val; }
	
	bool operator ! () const { return ! m_val; }
	
private:
	S32 m_val;
};

const Bool Bool::T( true  );
const Bool Bool::F( false );

#define True	Bool::T
#define False	Bool::F

Which actually works pretty well and accomplishes most of what I want, but it's a little clumsy and doesn't work with C at all.

No comments:

old rants