thuai
6/9/2015 - 6:20 AM

fun with Obj-C "generics"

fun with Obj-C "generics"

@import Foundation;
#import "Function.h"

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        
        Function<NSString *, NSArray<NSString *> *> *stringSplitter = [[Function alloc] initWithBlock:^(NSString *str) {
            return [str componentsSeparatedByString:@","];
        }];
        
        // works (unspecified)
        NSArray *__unused result0 = [stringSplitter evaluateAt:@"hello,there"];
        
        // works (all NSStrings are NSObjects)
        NSArray<NSObject *> *__unused result1 = [stringSplitter evaluateAt:@"hello,there"];
        
        // warning: incompatible pointer types ... (not all NSStrings are NSMutableStrings)
        NSArray<NSMutableString *> *__unused result2 = [stringSplitter evaluateAt:@"hello,there"];
        
        // works (all NSMutableStrings are NSStrings)
        Function<NSMutableString *, NSArray<NSObject *> *> *__unused mutableStringSplitter = stringSplitter;
        
        // warning: incompatible pointer types ... (not all NSObjects are NSStrings)
        Function<NSObject *, NSArray<NSString *> *> *__unused arbitrarySplitter = stringSplitter;
        
        // warning: incompatible pointer types ... (not all NSStrings are NSMutableStrings)
        Function<NSString *, NSArray<NSMutableString *> *> *__unused stringSplitterToMutable = stringSplitter;
    }
    return 0;
}
// Unfortunately, the generated Swift interface is not very useful:

import Foundation

class Function : NSObject {
    
    init(block: (AnyObject) -> AnyObject)
    
    func evaluateAt(value: AnyObject) -> AnyObject
}
@import Foundation;


NS_ASSUME_NONNULL_BEGIN

@interface Function<__contravariant InType, __covariant OutType> : NSObject
{
    // interestingly, this does work here (though OutType & InType are not available in the @implementation)
    OutType (^_block)(InType);
}

- (instancetype)initWithBlock:(OutType (^)(InType))block;

- (OutType)evaluateAt:(InType)value;

@end

NS_ASSUME_NONNULL_END