views:

306

answers:

3

Hi I'm finding a way to enforce runtime type checking or such things in Objective-C on Cocoa.

This is my code sample. I expected runtime error about wrong assignment to variable 'b'. But it wasn't. Compiled and executed without any error.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 NSArray* a = [NSArray arrayWithObject: @"TEST"]; 
 NSURL* b = [a objectAtIndex:0]; 

    NSLog(@"Is this URL? %i", [b isKindOfClass:NSURL.class]);
    [pool drain];
    return 0;
}

// Console log after program execution:
// 2010-01-11 10:25:02.948 Type Checking[98473:a0f] Is this URL? 0

I surprised about there is no runtime type checking is there. Because I used all high level languages like VB, C#, Java, ActionScript... I don't know low-level language like C, so I can't sure this is right way... It was really hard to figuring out why there is no compile or runtime error. But I'm getting to understand this as a natural rule in real C world. But more strong type checking will help me a lot. Even only in debugging session. Is there any way to do this?

And if there is no runtime type checking, what kind of coding and debugging strategy do I have to use about wrong typed values? And what's the trade off between runtime type checking is or isn't?

+2  A: 

Well, there is run-time type checking, but it happens a little later. I assume you're expecting some sort of exception when you try to put an NSString instance into a NSURL* variable. Instead, you'll get the exception when you try to call any NSURL-specific methods on your NSString instance.

For example, if you try [b isFileURL] you'll get an exception like "NSString does not respond to selector 'isFileURL'".

It's also important to understand why there's no compile-time type checking in your example. Specifically, the lack of compile-time type checking is a unique and important property of the id type, which is what NSArray's -objectAtIndex: returns.

Darren
I see. No exception when assigning. And compiler checks strictly typed variables only. Not for id types. Thanks for reply.
Eonil
A: 

The NSObject Framework will often kick up a fuss when the type is wrong but you can manually check for the type and throw an exception:

if (![obj isKindOfClass:SomeObjectClass.class])
  [NSException raise:@"BadTypeException"
    format:@"Bad type at line %d", (int)__LINE__];
[obj xyz];

...

if (![obj conformsToProtocol:@protocol(SomeProtocol)])
  [NSException raise:@"BadTypeException"
    format:@"Bad type at line %d", (int)__LINE__];
[obj abc];

Edit: Removed previous section claiming that calls to non-existent methods return nil or zeroes; as Mark Bessey says, an exception is thrown (not zero returned) if a non-nil object does not implement a method.

martinr
If you call a non-implemented method, it raises an exception. Were you thinking of sending messages to a nil object reference? That does return nil.
Mark Bessey
Thanks Mark. I've made a fix to reflect that
martinr
The exact behaviour of sending an message that the receiver does not respond to is determined by the `forwardInvocation:` method. The default behaviour of this method is to call `doesNotRecogniseSelector:` on `self`, and the default behaviour of `doesNotRecogniseSelector:` is to raise an exception, however this behaviour can be overridden by subclasses, and therefore does not always raise an exception.
dreamlax
I accepted 'nil returns nil, and others throws exception' as basically. I'll remember this. Thanks to everyone!
Eonil
+1  A: 

Objective-C does have compile-time type checking for message arguments and return types, but it is somewhat looser than many other languages. One major difference is that collection classes like NSArray and NSDictiomary are generic. You can put any type of object into an NSArray - the elements don't have to be the same type. Therefore, there's no type-checking when adding or accessing elements.

There is no run-time type checking for variable assignment. I believe that is a performance short-cut. In general, it's not much of an issue. If the wrong type of value gets assigned to a variable, it'll eventually get sent a message it doesn't understand, which generates a pretty useful error message.

Mark Bessey
Thanks for reply. I also realized this fact with the error caused by the unknown message. I'll care about there even more.
Eonil