Created
December 16, 2010 21:09
-
-
Save kylesluder/744020 to your computer and use it in GitHub Desktop.
An idea for using typeof on selector types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// It would be great if we had a typeof analogue that worked for selectors and evaluated to the type of the method that matches that selector. | |
@interface Foo : NSObject | |
- (NSString *)aMethod:(CGFloat)arg1 withArgs:(NSString *)arg2; | |
@end | |
void exampleOne() { | |
Foo *f = [Foo new]; | |
NSString *s = (__typeof_msg__(f, @selector(aMethod:withArgs:))objc_msgSend)(f, 0, @"String"); | |
NSNumber *n = (__typeof_msg__(f, @selector(aMethod:withArgs:))objc_msgSend)(f, 1.0, @"Hi"); // error: returns NSString* | |
NSString *r = (__typeof_msg__(f, @selector(aMethod:withArgs:))objc_msgSend)(f, @"Hello", @"World"); // error: expected CGFloat for arg 2 | |
} | |
@interface Bar : NSObject | |
- (NSRect)aMethod:(id)arg1 withArgs:(char **)arg2; | |
@end | |
// The first argument is used to disambiguate between multiple methods with the same selector | |
void exampleThree() { | |
Foo *f = [Foo new]; | |
Bar *b = [Bar new]; | |
NSString *s = (__typeof_msg__(f, @selector(aMethod:withArgs:))objc_msgSend)(f, 3.14, @"Pi"); | |
NSRect z = (__typeof_msg__(Bar, @selector(aMethod:withArgs:))objc_msgSend)(b, f, NULL); // also accepts class names, searches for instance methods that match the selector | |
} | |
// A variant would allow for sending class messages | |
@interface Bar (ClassMethod) | |
+ (double)aMethod:(char **)arg1 withArgs:(NSError **)arg2; | |
@end | |
void exampleThree() { | |
Bar *b = [Bar new]; | |
char *s; NSError *e; | |
double l = (__typeof_msg__(b, @selector(aMethod:withArgs:))objc_msgSend)(b, &s, &e); // error: -[Bar aMethod:withArgs:] doesn't take char**,NSError** or return double | |
double qq = (__typeof_class_msg__(Bar, @selector(aMethod:withArgs:))objc_msgSend)(b, &s, &e); | |
double ll = (__typeof_class_msg__(b, @selector(aMethod:withArgs:))objc_msgSend)(b, &s, &e); // error: b is an instance, but __typeof_class_msg__ casts objc_msgSend to (double)(Class, char**, NSError**) | |
double xx = (__typeof_class_msg__(b, @selector(aMethod:withArgs:))objc_msgSend)([b class], &s, &e); // much better | |
} | |
// Could wrap it in a typesafe macro | |
#define TYPESAFE_MSGSEND(self, _cmd, ...) ((__typeof_msg__(self, _cmd))objc_msgSend)(self, _cmd, __VA_ARGS__)) | |
#define TYPESAFE_CLASS_MSGSEND(self, _cmd, ...) ((__typeof_class_msg__(self, _cmd))objc_msgSend)(self, _cmd, __VA_ARGS__)) | |
void exampleFour() { | |
Foo *f = [Foo new]; | |
TYPESAFE_MSGSEND(f, @selector(aMethod:withArgs:), [NSString string], [NSString string]); // error: expected CGFloat for arg 2 | |
char *c; NSError *e; | |
TYPESAFE_CLASS_MSGSEND(Bar, @selector(aMethod:withArgs:), &c, &e); | |
} | |
// And can store these function pointers as type-safe versions of objc_msgSend | |
void exampleFive(Foo *aFooInstance) { | |
static __typeof_msg__(Foo, @selector(aMethod:withArgs:)) foo_msgSend; | |
// note mismatch of first arg to __typeof_msg__. Above, it's the class name. Here, it's the instance. They mean the same thing | |
if (!foo_msgSend) | |
foo_msgSend = __typeof_msg__(f, @selector(aMethod:withArgs:)) dlsym(RTLD_DEFAULT, "fancy_optimized_msgSend"); | |
foo_msgSend(aFooInstance, 2.7, @"Euler's number"); | |
} | |
// You can use this to test for whether you should use objc_msgSend_fpret (and probably stret too, if I can figure out the syntax for a typeof expression for a function) | |
float floatReturn( /* accepts any args; this won't work in ObjC++ */ ); | |
void exampleSix() { | |
Foo *f = [Foo new]; | |
if (__builtin_types_compat_p(__typeof_msg__(Foo, @selector(aMethod:withArgs:)), typeof(floatReturn))) | |
float f = objc_msgSend_fpret(f, @selector(aMethod:withArgs:), 1.0, @"Float return"); | |
else | |
id o = objc_msgSend(f, @selector(aMethod:withArgs:), 2.0, @"Object return"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment