【问题标题】:Why must the last part of an Objective-C method name take an argument (when there is more than one part)?为什么 Objective-C 方法名称的最后一部分必须带一个参数(当有多个部分时)?
【发布时间】:2011-05-27 16:04:00
【问题描述】:

在 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)不会影响程序,也不是语言的表现力。实际上,带有无参数组件的程序与没有的程序是 alpha 等价的。因此,我对声明这样一个特性没有必要的答案不感兴趣(除非这是 Objective-C 设计者声明的原因;有没有人碰巧认识 Brad Cox 或 Tom Love?他们在这里吗?)或者说如何编写方法名称以便不需要该功能。主要的好处是可读性和可写性(就像可读性一样,只是......你知道),因为这意味着你可以编写更接近自然语言句子的方法名称。 -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication 之类的东西(Matt Gallagher 指出 on "Cocoa With Love" 在删除形式参数时会有点混乱)可以命名为 -(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;
}

【问题讨论】:

  • 无法解释不可能的原因,但为什么会这样呢? Apple 会将方法命名为“takeAndRun:”和“takeAndDontComplain:”;)
  • takeAndRunWith:(id)theMoneytakeAndDon'tComplainAbout:(id)yourMedicine。当然,语法上很尴尬。
  • 感谢您提出这个问题——这是一个非常有趣的问题。我去问问。
  • 偶尔强迫的语法尴尬让我想要这个功能。
  • 好问题。顺便说一句,编译器对这样命名的方法没有问题:- (void) :(id)theMoney;- (void) :(id)obj1 :(id)obj2;。所以选择器只包含冒号就可以了。 ;-)

标签: objective-c selector language-design


【解决方案1】:

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

【讨论】:

  • 谢谢,布拉德。我对你的回答的解释是一样的;没有考虑离开 SmallTalk。
【解决方案2】:

21 年的 Objective-C 编程经验,我从未想过这个问题。给定语言设计,编译器是对的,运行时函数是错的()。

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

不用多想,我敢打赌,有一些语法错误并没有强制执行当前的模式。至少,它会使编译器更难编写,因为任何具有与表达式交错的可选元素的语法总是更难解析。甚至可能有一个边缘案例可以完全阻止它。当然,Obj-C++ 会使其更具挑战性,但直到基本语法已经确定多年后,它才与语言集成。

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

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


我向 Brad Cox 询问了此事,他非常慷慨地详细回答(谢谢,Brad!!):

我当时专注于 复制尽可能多的 Smalltalk 可能在 C 中并这样做 尽可能高效。任何备用 周期变成了普通 消息传递速度快。没有任何想法 一个专门的消息传递选项 (“reallyFast?” [bbum:我问使用'doSomething:withSomething:reallyFast' 作为例子])因为普通 消息已经和他们一样快了 可能。这涉及手动调整 C的汇编输出 proto-messager,这是一个 便携性的噩梦,如果不是的话 所有这些后来都被拿出来了。我愿意 回想一下被手动破解的消息器是 非常快;关于两个人的费用 函数调用;一个进入 消息者逻辑和其余的做 方法查找一次。
静态类型增强是后来的 添加在 Smalltalk 的纯 Steve Naroff 的动态类型和 其他。我只有有限的参与 在那。

去阅读布拉德的答案!

【讨论】:

  • 语法 bugaboos 让我非常感兴趣。
  • 在我看来,如果你有一大块没有冒号的方法名,你就会遇到解析问题,因为你不能确定它是否打算成为方法名的一部分.
  • 当我第一次为委托设计一个协议时,我突然想到了这个协议,这距离我开始使用 Objective-C 不到 21 年。正常模式是提供发送委托消息的对象作为第一个参数。例如-myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar。如果协议中有一个不需要其他参数的方法,这会导致方法名称的不一致。有关示例,请参见 NSTableViewDataSource。一种方法没有遵循所有其他方法的整洁模式。
【解决方案3】:

仅供参考,运行时实际上并不关心选择器,任何 C 字符串都是有效的,您也可以制作这样的选择器:“==+===+---__--¨ ¨¨¨¨^:::::::" 没有参数运行时将接受它,编译器不能,否则无法解析。对于选择器,绝对没有完整性检查。

【讨论】:

  • +1 我以为你提出这个建议简直是疯了,但你是对的。对于那些不相信的人:pastie.org/1388361
【解决方案4】:

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

如果你想要多词无参数选择器,为什么要多加一个词呢?有人可能会问这个

 [axolotl perform selector: Y with object: Y]

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

【讨论】:

  • 我曾想过“他们不需要”的说法,但我对此并不感兴趣。更新的问题使这一点更清楚。允许任意选择器组件不带参数提供的可写性较少,因为空格和驼峰式大小写之间的差异小于最终的无参数组件与重写自然语言语句和重新定位参数之间的差异(两者都必须完成)与 ObjC 一样)。
  • 此外,允许任意无参数组件会增加关键字冲突的可能性并使名称解析复杂化,尤其是在混合 C++ 和 ObjC 时(andor 将是特别的绊脚石)。如果只允许方法名的最后一个组件没有参数,这种情况就会少得多,因为它往往由多个单词组成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 2015-09-30
  • 2014-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
相关资源
最近更新 更多