Disable passing id-typed objects as params


#1

Is there any way to disable passing id-typed objects as params in method invocations?

I have discovered that the compiler is keeping quiet when I pass id-typed objects as params in method invocations even when the signature of the method specifies a specific class type.

For example, in the following example, I was expecting the errors in cases (1) and (2) but I am getting no errors in cases (3), (4), (5), and (6) contrary to my expectation (where I pass objects of type id to [MyWidgetArray addMyWidget:(MyWidget *)widget]

//  main.m

#import <Foundation/Foundation.h>
#import "MyWidgetArray.h"

int main (int argc, const char * argv[])
{
    @autoreleasepool {
                
        MyWidgetArray *widgetArray = [[[MyWidgetArray alloc] init] autorelease];
        
        NSArray *array = [NSArray array];
        [widgetArray addMyWidget:array];   // (1) Compile error as expected
        
        NSString *string = [NSString string];
        [widgetArray addMyWidget:string];  // (2) Compile error as expected
        
        MyWidget *widget = [[[MyWidget alloc] init] autorelease];
        [widgetArray addMyWidget:widget];
        
        // Is there any way to get the compiler to complain in the following cases?
        // I was horrified when I discovered that there are no compilation errors in those cases.
        {
            id array = [NSArray array];
            [widgetArray addMyWidget:array];  // (3) No compile error!

            id string = [NSString string];    
            [widgetArray addMyWidget:string]; // (4) No compile error!

            [widgetArray addMyWidget:[NSArray array]];    // (5) No compile error!
            [widgetArray addMyWidget:[NSString string]];  // (6) No compile error!
        }
    }
    return 0;
}
//  MyWidgetArray.h - An array for only MyWidget objects

#import <Foundation/Foundation.h>

@interface MyWidget: NSObject
@end

@interface MyWidgetArray : NSObject

- (NSUInteger)count;
- (void)addMyWidget:(MyWidget *)widget;
- (MyWidget *)myWidgetAtIndex:(NSUInteger)index;

@end
//  MyWidgetArray.m - An array for only MyWidget objects

#import "MyWidgetArray.h"

// Hiding the array object from the user
//
@interface MyWidgetArray ()
@property (nonatomic, retain) NSMutableArray *array;
@end

@implementation MyWidgetArray

@synthesize array;

- (void)dealloc
{
    self.array = nil;
    [super dealloc];
}

- (id)init
{
    self = [super init];
    if (self)
    {
        self.array = [NSMutableArray array];
    }
    return self;
}

- (NSUInteger)count
{
    return [array count];
}

- (void)addMyWidget:(MyWidget *)widget
{
    // Allow only instances of MyWidget    
    if ([widget isMemberOfClass:[MyWidget class]])
        [array addObject:widget];
}

- (MyWidget *)myWidgetAtIndex:(NSUInteger)index
{
    assert (index < [array count]);
    return [array objectAtIndex:index];
}

@end

@implementation MyWidget

@end

#2

Hi!

As far as I know, there’s no flag you can turn on to enable that kind of warning. “id” in Objective-C is special, being the wildcard of types. By disallowing id passing, you couldn’t do something like:

because init returns an id.

If you really absolutely cannot have non-MyWidgets in the collection, then you’ll need to check the type in addMyWidget: (e… isKindOfClass:) at runtime and then throw an exception (or something carrying a similar level of smackdownitude)

Cheers,
++md