В Objective-C вы не можете объявлять имена методов, где последний компонент не принимает аргумент. Например, следующее незаконно.
-(void)take:(id)theMoney andRun;
-(void)take:(id)yourMedicine andDontComplain;
Почему был разработан Objective-C таким образом? Это был просто артефакт Smalltalk, от которого никто не видел, что нужно избавиться?
Это ограничение имеет смысл в Smalltalk, поскольку Smalltalk не имеет разделителей вокруг вызова сообщений, поэтому последний компонент будет интерпретироваться как унарное сообщение для последнего аргумента. Например, BillyAndBobby take:'$100' andRun
будет анализироваться как BillyAndBobby take:('$100' andRun)
. Это не имеет значения в Objective-C, где требуются квадратные скобки.
Поддержка безпараллельных селекторных компонентов не принесет нам большого значения во всех обычных способах измерения языка, поскольку имя метода, которое выбирает программист (например, runWith:
, а не take:andRun
), не влияет на функциональную семантику программы или выразительности языка. Действительно, программа с безпараллельными компонентами альфа эквивалентна одной без. Я, таким образом, не интересуюсь ответами, в которых утверждается, что такая функция не нужна (если только это не было изложено в конструкторах Objective-C, кто-нибудь случайно знает Брэда Кокса или Тома Лава?) как писать имена методов, поэтому функция не нужна. Основное преимущество - читаемость и возможность записи (что похоже на читаемость, только... вы знаете), поскольку это означало бы, что вы могли бы писать имена методов, которые еще более напоминают предложения на языке естественного языка. Подобно -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
(который Мэтт Галлахер указывает на "Cocoa With Love" немного запутанно, когда вы отбрасываете формальный параметр), можно назвать -(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed
, тем самым помещая параметр непосредственно рядом с соответствующим существительным.
Apple Objective-C runtime (например) отлично справляется с этими типами селекторов, так почему же не компилятор? Почему бы не поддержать их в именах методов?
#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;
}