Friday, March 23, 2007

The BOOLs, They Do Nothing

From <CarbonCore/MacTypes.h>:
// kInvalidID  KernelID: NULL is for pointers as kInvalidID is for ID's

#define kInvalidID 0

So I should say-

if (someID == kInvalidID)

instead of-

if (!someID) ?

OK yea, I'll get right on that.

Seriously, every time i start to think that NS X rocks, I find some lameass redefinition like this. Zero is zero- am I missing something? Is this really just a Carbon relic, as the filename implies? Is it going away soon?


Daniel Jalkut said...

Zero is zero, but abstraction is still a good thing, usually. Yes, this might be the crufty old Carbon engineer in me speaking, but what you're observing are a couple "generally good" habits at work:

1. Define even obvious constants. It's not very likely that the numeric representation for "invalid ID" will change. But what if, for some reason, it does? Now your mess of "if !someID" tests are useless, while the conscientous programmer who compared with the constant is still in good shape. The other thing defining constants does is give you an easy way to make your code self documenting. Code that says "if !" simply means "if the opposite of whatever variable I'm testing." What does "the opposite" mean? It's clearer to a reader who doesn't know your code what "kInvalidID" means.

2. NULL vs. nil vs. 0. These are all names for zero. They are useful again mostly for the reason that they are self-documenting. NULL is a C pointer that happens to be zero. nil is an ObjectiveC object pointer that happens to be zero. And 0 is just the number zero, no other connotations assumed.

Blake C. said...

The self-documenting thing sounds nice. Guess I'm just stuck in the past :)

Brian said...

In Carbon, I spent a lot of time looking up other peoples code who put 0 where they could have put noErr of OSStatus. Or 1 means kCFCompareCaseInsensitive, kCFCompareBackwards is 4, and so on. Explicit is good. And can be literate programming. On the other hand, Blake, in the case you state, I agree (!whatever) is more literate.

Blake C. said...

Brian- I do use noErr, and the enumerated constants you mentioned always make life easier. What I never understood was all the redefintions of zero, outside of enums.

Redefining zero as noErr passed my test because of the varying conventions used by error-returning functions in bsd, mach, the old toolbox, etc. Not to mention system calls.

While Dan makes a good point about possible future redefinition of "kInvalidID"(and in theory I completely agree), I can't imagine that Apple or anyone else would ever move away from using zero to represent a null pointer. It's too ingrained in our history, and would break countless apps.

And just to stay in character, I'll try to maintain this opinion as I approach senility, and the kids these days move to python and other obscenely high-level languages :P

Uli Kusterer said...

I often have to work with other peoples' code where I have a numeric quantity and can't find what the valid range for those numbers is. Sometimes 0 is a valid value. Sometimes it's an invalid value, sometimes it means "the first object" or "the last object".

If you define constants *even when it's the obvious case* of an invalid value, readers will be certain that 0 is the invalid value. Otherwise, it could just be the first object, or a valid value that's needed in this place for some reason that escapes you... who knows?

It's like being the boss of an employee that never communicates: With someone who tells you every time he did something that he's finished, you'll immediately know that quiet means not good. With an employee that just disappears in a hole of silence, everything could be good, or this could be the slipping deadline.

Uli Kusterer said...

Example: For array indexes, sometimes 0 is valid, and -1 is invalid, sometimes the indexes are 1-based and 0 is invalid. By using kInvalidIndex, the reader will know it's not the first object, but an invalid one in a 1-based list.

Blake C. said...

Good point about the 1-based arrays, I hadn't thought of that. I heard that they exist somewhere, but my low level snobbery has kept me shielded from them, i guess :)

And I love the employee analogy.

Amin Negm-Awad said...

There's another thing to point out beside "easy-to-read code"

Zero is zero. That's correct …
An invalid object is zero? That's implementation.

So, it is not wrong to assume, that zero is zero, but that an invalid object is zero.