W Objective-C nie można zadeklarować nazw metod, w których ostatni składnik nie przyjmuje argumentu. Na przykład poniższy kod jest niedozwolony.
-(void)take:(id)theMoney andRun;
-(void)take:(id)yourMedicine andDontComplain;
Dlaczego Objective-C został zaprojektowany w ten sposób? Czy to tylko artefakt Smalltalk, którego nikt nie widział potrzeby się pozbyć?
To ograniczenie ma sens w Smalltalk, ponieważ Smalltalk nie ma ograniczników wokół wywołania wiadomości, więc ostatni składnik byłby interpretowany jako jednoargumentowa wiadomość do ostatniego argumentu. Na przykład BillyAndBobby take:'$100' andRun
zostanie przeanalizowany jako BillyAndBobby take:('$100' andRun)
. Nie ma to znaczenia w Objective-C, gdzie wymagane są nawiasy kwadratowe.
Wspieranie komponentów selektora bez parametrów nie dałoby nam wiele we wszystkich typowych sposobach mierzenia języka, ponieważ nazwa metody, którą wybiera programista (np. runWith:
Zamiasttake:andRun
) nie wpływa na semantykę funkcjonalną programu ani na ekspresję języka. Rzeczywiście, program z komponentami bez parametrów jest alfa równoważny programowi bez. Dlatego nie interesują mnie odpowiedzi, które stwierdzają, że taka funkcja nie jest konieczna (chyba że takie były powody projektantów Objective-C; czy ktoś zdarzyło się znać Brada Coxa lub Toma Love? Czy oni tu są?) Lub które mówią jak pisać nazwy metod, aby funkcja nie była potrzebna. Podstawową zaletą jest czytelność i zapisywalność (co jest jak czytelność, tylko ... wiesz), ponieważ oznaczałoby to, że możesz pisać nazwy metod, które jeszcze bardziej przypominają zdania w języku naturalnym. Takie jak -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
(na co Matt Gallagher zwraca uwagę w „Cocoa With Love”-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed
, umieszczając w ten sposób parametr bezpośrednio obok odpowiedniego rzeczownika.
Środowisko uruchomieniowe Objective-C firmy Apple (na przykład) doskonale radzi sobie z tego rodzaju selektorami, więc dlaczego nie kompilator? Dlaczego nie wspierać ich również w nazwach metod?
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Potrzebie : NSObject
-(void)take:(id)thing;
@end
@implementation Potrzebie
+(void)initialize {
SEL take_andRun = NSSelectorFromString(@"take:andRun");
IMP take_ = class_getMethodImplementation(self, @selector(take:));
if (take_) {
if (NO == class_addMethod(self, take_andRun, take_, "@@:@")) {
NSLog(@"Couldn't add selector '%@' to class %s.",
NSStringFromSelector(take_andRun),
class_getName(self));
}
} else {
NSLog(@"Couldn't find method 'take:'.");
}
}
-(void)take:(id)thing {
NSLog(@"-take: (actually %@) %@",NSStringFromSelector(_cmd), thing);
}
@end
int main() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Potrzebie *axolotl=[[Potrzebie alloc] init];
[axolotl take:@"paradichloroaminobenzaldehyde"];
[axolotl performSelector:NSSelectorFromString(@"take:andRun")
withObject:@"$100"];
[axolotl release];
[pool release];
return 0;
}