5

I've seen a lot of ObjC code which do:

obj = [[SomeObject alloc] init];
if (obj) {
/// ...
}

but as I understood it, the value inside () is a boolean, and 0 indicates FALSE 1 indicates TRUE(there is another case in other language that 0 is true and 1 is false), and if a pointer does not point to anything, it is set to NULL(nil), which is #defined to be 0, so I wonder is it better if I do:

if (obj != nil) {
/// ...
}

as it IS checking if the obj is nil or not, no matter what value nil is, so it does not rely on that nil (or NULL) happen to be defined as 0?

Daniel
  • 23,129
  • 12
  • 109
  • 154
hzxu
  • 5,753
  • 11
  • 60
  • 95

2 Answers2

5

edit: after testing a bit, I have determined that modern compilers will actually create the same machine code for both cases;

orig post:

It is (negligibly, perhaps) more efficient to use

if(obj) {

since you do not need to create the intermediary boolean value (by evaluating the comparison expression). I'm not sure which "other language" you are referring to regarding the non-zero being FALSE; the closest thing I can think of is c programs returning 0 for "success" and anything else for "error". Every modern language I have ever worked with uses 0 as FALSE and any non zero value for TRUE.

In Objective-C, nil is literally 0 (treated like a pointer). It is not just a pointer to zero, it is zero as a pointer. It is therefore reliably equivalent to FALSE (or, in our nomenclature "NO").

edit after testing a bit, I have determined that modern compilers will actually create the same machine code for both cases; probably because nil is essentiall typedef'd to 0, so it knows the two styles of checking are both saying "if this pointer is non-zero".

Chris Trahey
  • 18,202
  • 1
  • 42
  • 55
  • `nil` decomposes to `0` (just an integer) and a compiler should be able to compile `if(obj != 0)` and `if (obj)` to equivalent (if not identical) instructions .. –  Aug 06 '12 at 00:36
  • Have you checked the assembly code? The two generate absolutely identical code.... – lnafziger Aug 06 '12 at 00:38
  • Yes, I just finished checking the machine code, and it is indeed identical. – Chris Trahey Aug 06 '12 at 00:40
  • (full disclosure: I checked with gcc and c code, my Xcode on this machine is out-of-date. Though I can only assume llvm is doing the same) – Chris Trahey Aug 06 '12 at 00:41
  • @ctrahey - No need to qualify "compiler" with "modern" here. When a boolean-valued expression occurs in a branching context compilers do not need to generate a boolean at all, they just generate branching code - this optimisation is as old as compilers. This is also why `if(obj)` and `if(obj != nil)` produce the same code, and why `if(x == 42)` doesn't involve two comparisons (to 42 to produce a boolean and then on the resulting boolean to do the branch). – CRD Dec 13 '13 at 19:20
  • @CRD I'm not sure if I would call that an "optimization". OP didn't write `if ((ptr != nil) == true)`... That's why the discussion about the boolean temporary isn't relevant either. –  Dec 13 '13 at 19:24
  • @H2CO3 - The *statement* requires a test/branch of some sort, it can either be independent of evaluating the expression or merged into it, the latter is the optimisation. Compiler's typically have two (logical) code paths for the two value & branching scenarios so they can apply these optimisations. Take a look at your favourite text on compiler writing. Also see the C Standard - relational & equality operators return `0` or `1`, so the expr `x == 42` by defn returns `0`/`1`, and when used in an `if` that `0`/`1` determines the branch. However compilers *optimise out* the intermediate `0`/`1` – CRD Dec 13 '13 at 21:09
  • 1
    @CRD I don't know if you see writing very well from the top of your high horse, but [I've already written a compiler](https://github.com/H2CO3/Sparkling/blob/master/src/compiler.c). Yes, the 0/1 determines the branch. But that doesn't *need* a comparison. –  Dec 13 '13 at 21:16
  • @H2CO3 - :-) Youth, I remember it well (it wasn't long ago). First, it depends on the architecture whether a separate (test/compare) instruction is required or not. But that is not the point, in `if(obj != nil)` the language *by definition* produces a `0` or `1` which *the compiler optimises* away. Let's call it a day. – CRD Dec 13 '13 at 21:25
3

0 indicates FALSE 1 indicates TRUE

Close. In C (and Objective-C), a 0 evaluates to false, and a non-zero evaluates to true. So a nil (or NULL) pointer is "false", but any non-nil pointer is "true".

Your examples are essentially equivalent; neither is "better" than the other (unless you or your codebase has a style preference).

mipadi
  • 398,885
  • 90
  • 523
  • 479