为什么Objective-C方法名称的最后一部分必须带参数(当有多个部分时)?

out*_*tis 89 language-design objective-c selector

在Objective-C中,您不能声明最后一个组件不带参数的方法名称.例如,以下是非法的.

-(void)take:(id)theMoney andRun;
-(void)take:(id)yourMedicine andDontComplain;
Run Code Online (Sandbox Code Playgroud)

为什么Objective-C是这样设计的?它只是Smalltalk的神器,没有人看到需要摆脱?

这种限制在Smalltalk中是有意义的,因为Smalltalk没有围绕消息调用的分隔符,因此最终组件将被解释为到最后一个参数的一元消息.例如,BillyAndBobby take:'$100' andRun将被解析为BillyAndBobby take:('$100' andRun).这在Objective-C中无关紧要,其中需要使用方括号.

支持无参数选择器组件在测量语言的所有常用方式中都不会获得太多,因为程序员选择的方法名称(例如,runWith:而不是take:andRun)不影响程序的功能语义,也不影响语言的表达性.实际上,具有无参数组件的程序与没有参数的组件相当.因此,我对那些没有必要说明这样一个特征的答案不感兴趣(除非那是Objective-C设计师所说的原因;有没有人碰巧知道Brad Cox或Tom Love?他们在这里吗?)或者说如何编写方法名称,以便不需要该功能.主要的好处是可读性和可写性(这就像可读性,只有......你知道),因为这意味着你可以编写更接近自然语言句子的方法名称.这样的人-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(马特·加拉格尔指出的"可可的爱"可以被命名为当您拖动一个形式参数是有点混乱)-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed,从而将参数紧邻适当的名词.

Apple的Objective-C运行时(例如)完全能够处理这些选择器,那么编译器为什么不呢?为什么不在方法名称中支持它们呢?

#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;
}
Run Code Online (Sandbox Code Playgroud)

小智 111

这是布拉德考克斯.我原来的答案误解了这个问题.我认为,真的是一个硬编码扩展来触发更快的消息传递,而不是一种语法糖.真正的答案是Smalltalk不支持它,可能是因为它的解析器无法处理(假设的)模糊性.虽然OC的方括号可以消除任何歧义,但我根本没想到偏离Smalltalk的关键字结构.


bbu*_*bum 42

21年的Objective-C编程,这个问题从未在我脑海中浮现.鉴于语言设计,编译器是正确的,运行时函数是错误的().

带有方法名称的交错参数的概念总是意味着,如果至少有一个参数,则最后一个参数始终是方法调用语法的最后一部分.

如果不考虑它,我敢打赌,有一些语法错误,没有强制执行当前的模式.至少,它会使编译器更难写入任何具有与表达式交错的可选元素的语法总是难以解析.甚至可能有一个扁平的边缘情况阻止它.当然,Obj-C++会让它变得更具挑战性,但是在基础语法已经完成之后的几年里,它还没有与语言集成.

至于为什么Objective-C是这样设计的,我怀疑答案是该语言的原始设计者不考虑允许交错语法超越最后一个参数.

这是最好的猜测.当我发现更多时,我会问他们其中一个并更新我的答案.


我问布拉德考克斯这个问题,他非常慷慨地详细回复(谢谢,布拉德!!):

当时我专注于在C中尽可能多地复制Smalltalk并尽可能高效地完成.任何备用周期都可以快速进行普通消息传递.没有想到专门的消息传递选项("真的很快?"[ bbum:我问过'doSomething:withSomething:reallyFast'作为例子 ])因为普通消息已经尽可能快.这涉及手动调整C proto-messager的汇编程序输出,这是一个可移植性的噩梦,如果不是所有这些都被后来取出了.我记得手被黑的消息是非常快的; 关于两个函数调用的成本; 一个进入消息逻辑,其余用于在那里进行方法查找.
静态类型增强功能后来被添加到了Smalltalk的Steve Naroff和其他人的纯动态类型之上.我只有有限的参与.

去读Brad的答案吧!

  • 我第一次为代表设计了一个协议,这是在我开始使用Objective-C后不到21年的时间.正常模式是将发送委托消息的对象作为第一个参数提供.例如`-myObjectWithDelegate:(id)foo wantsYouToDoSomethingWith:(id)bar`.如果您在协议中有一个不需要其他参数的方法,这会导致方法名称的不一致.有关示例,请参阅NSTableViewDataSource.一种方法不遵循所有其他方法的漂亮整洁模式. (2认同)

Psy*_*cho 21

仅仅为了你的信息,运行时实际上并不关心选择器,任何C字符串都是有效的,你也可以创建一个这样的选择器:"== + === + ---__--¨¨¨¨ ¨^ ::::::"没有参数,运行时会接受它,编译器就是不能,否则它就不可能解析了.对于选择器,绝对没有健全性检查.

  • +1我认为你提出这个问题是完全疯了,但你是对的.对于那些不相信的人:http://pastie.org/1388361 (7认同)

Mar*_*wis 6

我认为它们在Objective-C中不受支持,因为它们在Smalltalk中也不可用.但这与你的想法有不同的原因:它们不是必需的.需要的是支持具有0,1,2,3,...参数的方法.对于每个参数的数量,已经有一种工作语法来调用它们.添加任何其他语法只会导致不必要的混淆.

如果你想要多字无参数选择器,为什么要用一个额外的单词来停止?然后人们可能会问

 [axolotl perform selector: Y with object: Y]
Run Code Online (Sandbox Code Playgroud)

也得到支持(即选择器是一个单词序列,一些有冒号和一个参数,有些则没有).虽然这是可能的,但我认为没有人认为这是值得的.