Do Apple templates contain a bug since they cast to BOOL? - objective-c

According to Mike Ash's blog post casting to BOOL can fail 6% of the time since a pointer is larger than a BOOL. Because of this he recommends that if you are checking if an object exists you should check against nil
if (self != nil) {
instead of what Apple templates do which is
if (self) {
Do Apple's templates contain a bug or is there some other syntactical sugar I don't know about?

since they cast to BOOL
No, they don't. There is no cast performed at all. There is, however, evaluation of an expression as a logic value. In the case of pointers (which nil and self are), a NULL pointer evaluates to false, anything else to true. This is not a bug, just a shorthand way and it's perfectly valid C.
Concerning why one might want to perform an explicit comparison against NULL or nil: in some cases, it may be more readable, especially if it's not obvious at first glance of what type and range the expression is. However, in Objective-C and Cocoa, it's such a common idiom in a constructor to do this, that any experienced programmer will grasp it without problem.

Objective-C is based on C, and in C the if statement does, maybe surprisingly, not operate on boolean values.
C has a hierarchy of types:
The char, integer, and enumeration (enum) types are the integer types
The float, double and long double are the real floating types
There are three complex number types which together with the real floating types are termed simply the floating point types
The integer types and floating point types combined form the arithmetic types
The arithmetic types along with the pointer types form the scalar types
Phew!
Now to the if statement, it is of one of the forms:
if ( expression ) statement
if ( expression ) statement else statement
Where expression must be of any scalar type. The first (or only) statement is executed if the expression compares unequal to 0, the second (if present) statement is executed if the expression compares equal to 0.
So:
if (self) ...
and
if (self != nil) ...
are identical in result.
The first expression self is some pointer type, which is a scalar type, and is compared for being unequal to the zero of the pointer type (represented in code by nil). The second expression self != nil is an equality-expression and yields either 0 or 1 of type int, which is also a scalar type...
So technically the second form involves the intermediate production of an int value, but no compiler will actually produce one (unless you assign the result of the expression to a variable of course).
Notes:
Somewhat bizarrely if ( sin( angle ) ) ... is valid...
The switch statement operates on integer types and not scalar types
HTH

No, this can't fail if the pointer isn't nil, it's safe and the only difference is the syntax, and I wouldn't recommend one or another way, since they're the same.
You aren't casting self to a BOOL, you' re just checking if self is different from zero.

Edited
As per Martin's comment I was logging wrong debug messages.
It's the same
Here is a simple test
NSString *str = nil;
// suppose our string points to a string object whose starting address is 0x4500
//I'm assigning it manually so that I can test
str = 0x4500;
NSLog(#"%d",str);
if (str) {
NSLog(#"It's non-nil");
}
else {
NSLog(#"It's nil");
}
if (str == nil) {
NSLog(#"It's nil");
}
else {
NSLog(#"It's non-nil");
}
Output is :
It's non-nil
It's non-nil

Related

Using && in a return statement causes it to become a type of int?

+ (id)checkWithBlock:(BOOL (^)(id))block
{
return [[[OCMBlockConstraint alloc] initWithConstraintBlock:block] autorelease];
}
[OCMArg checkWithBlock:^(id value) { return YES && YES; }];
I am passing in a return YES && YES to a block that returns a BOOL, and yet am getting this error:
Incompatible block pointer types sending 'int (^)(__strong id)' to parameter of type 'BOOL (^)(__strong id)'
You're missing the BOOL declaration when calling the block method. If you use Xcode's autocomplete, it should create this for you:
[OCMArg checkWithBlock:^BOOL(id value) {
return YES && YES;
}];
There is an answer and there is a good comment. However, we have to put things together to understand that:
A. In C the result of a logical and operation is an int. From the standard (ISO/IEC 9899:TC3):
Semantics
The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.
B. Someone at Apple decided to have inferred types for blocks and stronger typing. This is a bad idea for C, because C does not support inferred types and is weakly typed. It solves the category of problems you have with implicit (or explicit) castings (weak typing), not with type inference and type strength. So the type strength of blocks does not fit for C.
C. Solution #1 (old): The original solution was, to explicitly cast the return value:
return (BOOL)(YES && YES);
D. Solution #2 (new): Later that many developers complained Apple for having un-C-ish strong typing combined with type inference for blocks that Apple introduced an explicit return type for blocks as in remus' answer. If you have such an explicit type, return expressions are implicitly casted to that type.
Z. The funny part of the story: Even Apple failed with that inferred types they try it again in Swift. And there it is much more complex and obfuscated if you have more than 1+2. One of the "cool feature you should use sparingly" stuff in Swift.

Override truth or ! operator in Objective-C

How do I override the truth-value of my class instance, or its ! operator?
For example (simplified names/usage):
MyClass variable = [MyClass alloc] initWithValue: nil];
...
if (!variable) { NSLog(#"'Not variable value' works"); }
I've searched for two possible solutions but couldn't find anything useful. In some languages i would overload an isTrue, asBool, etc function; or override the unary ! operator FOR THAT CLASS (not the main NOT operator.
My initial reaction to this problem was: You don't need to in Objective-C, you're going at it wrong. While true, I have lost over hours debugging some code that had the above (!variable) instead of
if (!variable.value) { NSLog(#"'Not variable value' works"); }
MyClass has property value among many others, which you can set or not. It defines whether or not you do something so it is common to need if (!variable.value){ NSLog(#"Warning, value not set"); }
So I want to overload the ! or isTrue function to check whether or not variable.value is set instead of merely checking if variable is linked to an address. This would make my code more readable and make my class more useable.
To be clear, in this example, variable points to an alloc-init'ed object, where variable.value = nil for example.
For example this can be done in python by overloading __ nonzero __.
As a side question that would answer this question: How does the truth value of an object work in Objective-C?
You can't override these things in ObjC. ObjC behaves just like C in this regard-- object references are pointers, either valid or nil-- a nil value evaluates to NO in a boolean expression and any non-nil value will appear as YES.
The canonical check for "is this thing an invalid pointer" is if (!thing) { ... }.
If you are always doing this:
if (!variable.value) ...
then perhaps variable is of type NSNumber or some object container for a primitive? It's hard to tell without context what pattern you're using and whether there's a better idiom for this.
An object in Objective-C has the same meaning in a boolean expression as a pointer in C, because it is a C pointer. If the pointer is NULL -- or nil for an object -- then it's false; otherwise it's true.
You can't override operators in Objective-C.
This said, !variable.value does indeed test whether value is nil (assuming that value has an object type) -- the dot operator resolves to a message send [variable value] whose return value is then negated.

Comparing Objects Directly to nil

I have seen many posts here on Stack Overflow warning Objective-C users not to compare objects with the == operator. For example, the following is always recommended against.
if (string1 == string2) {} // string1 and string2 are both of type NSString *
I understand this warning as the == operator in this case checks for pointer equality, not the actual values of string1 and string2. If this is the case, why do I so often see people comparing their objects to nil with the == operator. For example, I have seen the following several times.
if (obj == nil) {} // obj is of type id, or any other object
If comparing pointers with the == operator is bad practice on things like NSStrings (or NSNumbers or NSArrays etc), then why is it so commonplace with nil.
Is this the standard because there is only one type of nil i.e.: nil always equals nil? Why are direct comaprisons using the == operator frowned upon between objects, but let slip when comparing to nil?
Thank your for your time.
Using == tests for pointer equality, which seems to be what you want to test for in this particular case. You are checking whether some pointer is a nil pointer. Specifically, a pointer that equals zero. Comparing objects is more complicated as you've pointed out. Equality between objects often relies on some internal part of the two objects being "the same".
In the case of strings, "equality" can mean "has the same characters" but it could also mean "has the same characters (ignoring capitalization)". There are also cases where you might want a nil string to equal an empty string or even a string with just whitespace. The point is that you must understand the different methods of determining equality in order to implement your own definition of equality for your objects.
Note that checking for pointer equality is almost never what you want to use when comparing things like strings or arrays. There are some interesting optimizations that can throw you off. For example, all empty NSArray's point to the same singleton object.
nil is like NULL from C or std::nullptr in C++. Basically points to nothing.
When a object in Objective-C is unallocated (haven't been alloc), the pointer will be nil.
So if (obj == nil) will check if obj is allocated (or initialized as they often happen together)
This technique is often used when writing a custom initializer or checking if some object exists or not.

When does Objective-C implicitly cast to BOOL?

I read Mike Ash's Objective-C pitfalls page, and now I'm paranoid about implicitly casting variables of type id to BOOL.
Assume I have a 'dangerous' pointer with the lower bits zeroed out, so that casting it to a BOOL would produce NO even though it points to a valid object. Let's call this 'dangerous' pointer foo.
How do simple if statements work?
Does the if statement cast foo to a BOOL when it evaluates the condition? Or does it cast to a pure boolean?
if( foo )
{
[myArray addObject:foo];
}
Does it work the same way in ternary expressions?
// Does this break when foo is 'dangerous'?
self.titleLabel.hidden = foo ? YES : NO ;
Or will the ternary only break if I do this:
// I'm pretty sure it breaks now
self.titleLabel.hidden = ((BOOL)foo) ? YES : NO ;
I feel like I'm missing something basic about logical operations in C, and how they relate to BOOL. Please help enlighten me.
When does Objective-C implicitly cast to BOOL?
Never, since this phrase is semantically incorrect. A cast is, by definition, explicit. What you're asking about is called an "implicit type conversion" (coercion - thanks, Josh!).
Also, strictly speaking, the conditionals in Objective-C are not special: they're inherited from C. So expressions, when needed to evaluated as booleans, aren't treated as BOOL, but as int.
// Does this break when foo is 'dangerous'?`
self.titleLabel.hidden = foo ? YES : NO;
No, it doesn't. (expr) when used as a "boolean" expression, is equivalent to (expr != 0). No risks here.
// I'm pretty sure it breaks now
self.titleLabel.hidden = ((BOOL)foo) ? YES : NO;
Now this can break, since BOOL is just typedeffed to signed char, which is 8 bit on iOS. Thus, if foo, which is a (32-bit) pointer, gets truncated to 8 bits, and the lower 8 bits of the pointer were all zero, but the pointer itself wasn't nil, this will incorrectly report false. You don't want to do this superfluous, ugly and dangerous cast. If you want to be more explicit, write
var = (obj != nil) ? valueOne : valueTwo;
instead.
There's no casting in your first two samples. Writing if(expr) is equal to writing if(expr == 0).
Your third example might indeed break in some cases, as described in the article you refer to.

Why do functions use -(void) and not -(nil) in Obj-C?

In objective-C I often see functions that don't return anything declared as:
- (void)myFunction {…
But why aren't functions declared using nil, like this
- (nil)myFunction {…
Don't they both return "nothing"?
void is nothing. nil is something (0).
In other words, returning nil isn't the same as returning nothing.
Historically in languages belonging (syntactically) to the C-like language family, void indicates that there is no type being returned from a function.
More precisely, just as variables have (or belong to) a given type, functions also have types. For example, a function that returns a int, it is an int type function, or a function whose type is int. Same if it returns something else.
If the function does not return anything - it returns nothing - what type does it belongs to? It has no type, and the void type represents such a thing.
I'm not versed in Objective C, but if I understand correctly, nil is an typeless ID (or an id of any type), almost like a built-in implementation of the null pattern.
And null is a (void *) type, the later being a typeless pointer that can point to anything, just as it would in C and C++.
So a function that returns nil would imply that its type is an id of any type. Don't know if that even makes sense. So right then and there, (nil)myFunction is of a type completely different from (void)myFunction since the former has one type (any type?) whereas the later has no type at all.
Also, nil is a built-in constant. Returning nill is like saying that your function returns a specific number for instance ((1)myFunction). That wouldn't make any sense, would it?
Void is an object type. Void means there is no return value.
Nil is an object, not a type. It represents an empty value.