7

So, obviously, after WWDC I'm playing with new stuff presented during last week. As you know Apple introduced generics to the world of Objective-C

Note: This answer is somehow follow-up to this question: Are there strongly-typed collections in Objective-C?

I tried this code in method, works great

NSMutableArray<NSString*> *array = [[NSMutableArray alloc] init];

[array addObject:@""];
[array addObject:@(54)];Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString * __nonnull'
// Great, generics works as expected.

However I also have method I want to transform to generics

In header file:

- (NSArray <NSString*> *)objectsToSearch;

Implementation:

- (NSArray <NSString*> *)objectsToSearch
{
    NSString *first = @"1";

    NSString *second = @"2";

    NSString *third = @"3";

    NSNumber *test = @(55);

    return @[first, second, third, test]; // No-error!!!
}

Am I doing something wrong or Clang does not support generics + literals or there is something else I'm missing?

Community
  • 1
  • 1
lvp
  • 2,078
  • 18
  • 24
  • Yes you are doing something wrong, as you know! And yes the compiler should produce an error/warning. Xcode 7 is beta software, report it as a bug to Apple and hopefully they'll fix it. – CRD Jun 14 '15 at 11:21
  • Thanks for clarifying! – lvp Jun 14 '15 at 11:56
  • I don't believe it's a bug. See my large post below with sample code and why it's working correctly. – drekka Jun 19 '15 at 01:51

4 Answers4

12

I've just been diagnosing this some more and I don't think this is a bug. The following code shows a variety of options and why each will or will not compile. Note: This is based on my guesses as to how things work. It may be different to how Apple would explain it.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
-(void) testGenericArrays {

    NSString *aString = @"abc";
    NSNumber *aNumber = @(55);

    NSArray<NSString *> *arr1  = @[aString, aNumber];
    // Compiles because the RHS is an un-typed array at compilation time.

    NSArray<NSString *> *arr2  = @[aString, @(20)];
    // Compiles because the RHS is an un-typed array at compilation time.

    NSArray<NSString *> *arr3 = [NSArray<NSString *> arrayWithObjects:aString, aNumber, @(20), nil];
    // Compiles because the type erasure for arrayWithObjects only types the first argument which is a NSString.
    // The rest of the arguments are a vaList which is not checked during header processing.

    NSArray<NSString *> *arr4 = [NSArray<NSString *> arrayWithObjects:@(20), nil]; // <- Error!
    NSArray<NSString *> *arr5 = [NSArray<NSString *> arrayWithObjects:aNumber, nil]; // <- Error!
    // Neither of these two compile because the first argument is now a NSNumber and is checked.

    NSArray<NSString *> *arr6 = [NSArray<NSString *> arrayWithObject:aNumber]; // <- Error!
    // Doesn't compile because the argument is checked during header processing.

    NSArray<NSString *> *arr7 = [NSArray arrayWithObject:aNumber];
    // Compiles because the RHS is an un-typed array at compilation time.

    NSMutableArray<NSString *> *arr8 = [[NSMutableArray alloc] init];
    [arr8 addObject:aNumber]; // <- Error!
    // Doesn't compile because the LHS is a typed array and we are adding to it.
}
#pragma clang diagnostic pop

Hope this clarifies things for people. Feel free to cut and paste into a unit test and try it out for yourself.

drekka
  • 20,957
  • 14
  • 79
  • 135
3

Don't assume Apple is adding generics to Obj-C because they want to improve Obj-C. The real reason is that all iOS/OS X frameworks written in Obj-C are very difficult to use in Swift - you have to cast everything from AnyObject.

Adding generics to Obj-C enables Apple to tag the methods correctly, e.g.

@property(nonatomic, readonly, copy) NSArray <__kindof UIView *> *subviews

The important thing here is that now Swift can work with the frameworks much better. Implementing warnings/errors for misuse of generics in Obj-C is not that important so we can expect a lot of bugs there.

I advice you to report a bug but don't expect it to be fixed soon.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
0

I'd agree that this is a bug. I tested a simpler version of your case and it still fails.

NSString *first = @"1";
NSString *second = @"2";
NSString *third = @"3";
NSNumber *test = @(55);

NSArray <NSString*>* arr  = @[first, second, third, test, @(20)];

It doesn't seem to be an issue with the array literal syntax either. This line still produces no error.

NSArray <NSString*>* anotherArray = [NSArray arrayWithObjects:first, second, third, test, @(20), nil];
Connor Pearson
  • 63,902
  • 28
  • 145
  • 142
0

I just came across this post and I'm not getting the same results. I've cut and pasted the code into XCode to confirm and all the examples above produce errors (I have warnings set to errors). So I'm not seeing the bug. Either that or there is a compiler setting somewhere that's different between us.

drekka
  • 20,957
  • 14
  • 79
  • 135
  • I tried it with Xcode 7 beta, it succeeds to compile – Hai Feng Kao Jun 18 '15 at 07:39
  • I can't explain why it seems to work for some and not others. I've been using generics for the last week or so and they are creating all the compiler warnings I would expect them to create. I would suggest checking through build settings and this seems the most likely cause of the discrepancy to me. Perhaps it's because I have all warnings set to be errors that mine is working. – drekka Jun 19 '15 at 00:54
  • Forget my last comment. I'm checking some other things. – drekka Jun 19 '15 at 01:25