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

时间:2022-12-10 05:30:57

In Objective-C, you can't declare method names where the last component doesn't take an argument. For example, the following is illegal.

在Objective-C中,如果最后一个组件没有参数,则不能声明方法名。例如,以下内容是非法的。

-(void)take:(id)theMoney andRun;
-(void)take:(id)yourMedicine andDontComplain;

Why was Objective-C designed this way? Was it just an artifact of Smalltalk that no one saw a need to be rid of?

为什么Objective-C是这样设计的?难道这只是一种没有人认为需要摆脱的Smalltalk的产物吗?

This limitation makes sense in Smalltalk, since Smalltalk doesn't have delimiters around message invocation, so the final component would be interpreted as a unary message to the last argument. For example, BillyAndBobby take:'$100' andRun would be parsed as BillyAndBobby take:('$100' andRun). This doesn't matter in Objective-C where square brackets are required.

这种限制在Smalltalk中是有意义的,因为Smalltalk没有围绕消息调用的分隔符,所以最后的组件将被解释为对最后一个参数的一个一元消息。例如,BillyAndBobby take:“$100”andRun将被解析为BillyAndBobby take:(“$100”andRun)。这在Objective-C中并不重要因为需要方括号。

Supporting parameterless selector components wouldn't gain us much in all the usual ways a language is measured, as the method name a programmer picks (e.g. runWith: rather than take:andRun) doesn't affect the functional semantics of a program, nor the expressiveness of the language. Indeed, a program with parameterless components is alpha equivalent to one without. I'm thus not interested in answers that state such a feature isn't necessary (unless that was the stated reasons of the Objective-C designers; does anyone happen to know Brad Cox or Tom Love? Are they here?) or that say how to write method names so the feature isn't needed. The primary benefit is readability and writability (which is like readability, only... you know), as it would mean you could write method names that even more closely resemble natural language sentences. The likes of -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication (which Matt Gallagher points out on "Cocoa With Love" is a little bit confusing when you drop the formal parameter) could be named -(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed, thus placing the parameter immediately next to the appropriate noun.

支持无参数选择器组件不会像通常测量语言那样给我们带来很多好处,因为程序员选择的方法名(例如runWith:而不是take:andRun)不会影响程序的功能语义,也不会影响语言的表达性。实际上,一个没有参数的程序等于一个没有参数的程序。因此,我对不需要这样的特性的答案不感兴趣(除非这是Objective-C设计人员声明的原因;有没有人认识布拉德·考克斯或汤姆?它们在这里吗?)或者说如何编写方法名,这样就不需要这个特性了。主要的好处是可读性和可写性(就像可读性一样,只是……)你知道),因为这意味着你可以写出更接近自然语言句子的方法名。比如-(BOOL) applicationshould终止afterlastwindowclosed:(NSApplication*)这个应用程序(Matt Gallagher在“Cocoa With Love”中指出,当你删除正式参数时,这个应用程序有点让人困惑)可以命名为-(BOOL)应用程序:(NSApplication*)这个应用程序应该终止afterlastlastwindowclosed,从而将这个参数直接放在合适的名词旁边。

Apple's Objective-C runtime (for example) is perfectly capable of handling these kind of selectors, so why not the compiler? Why not support them in method names as well?

苹果的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;
}

4 个解决方案

#1


109  

This is Brad Cox. My original answer misunderstood the question. I assumed reallyFast was a hardcoded extension to trigger faster messaging, not a kind of syntactic sugar. The real answer is that Smalltalk didn't support it, perhaps because its parser couldn't deal with the (assumed) ambiguity. Although OC's square brackets would remove any ambiguity, I simply didn't think of departing from Smalltalk's keyword structure.

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

#2


42  

21 years of programming Objective-C and this question has never crossed my mind. Given the language design, the compiler is right and the runtime functions are wrong ().

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

The notion of interleaved arguments with method names has always meant that, if there is at least one argument, the last argument is always the last part of the method invocation syntax.

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

Without thinking it through terribly much, I'd bet there are some syntactic bugaboos with not enforcing the current pattern. At the least, it would make the compiler harder to write in that any syntax which has optional elements interleaved with expressions is always harder to parse. There might even be an edge case that flat out prevents it. Certainly, Obj-C++ would make it more challenging, but that wasn't integrated with the language until years after the base syntax was already set in stone.

如果不仔细考虑的话,我敢打赌一定会有一些语法上的麻烦,它们没有执行当前的模式。至少,它会使编译器更难编写,因为任何具有与表达式交叉的可选元素的语法总是更难解析。甚至可能有一种边缘情况可以防止这种情况的发生。当然,object - c++会使它更具有挑战性,但是直到基本语法被设置为石头之后,这才与语言集成。

As far as why Objective-C was designed this way, I'd suspect the answer is that the original designers of the language just didn't consider allowing the interleaved syntax to go beyond that last argument.

至于Objective-C被设计成这样的原因,我想答案是语言最初的设计者并没有考虑允许交叉语法超越最后的论点。

That is a best guess. I'll ask one of 'em and update my answer when I find out more.

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


I asked Brad Cox about this and he was very generous in responding in detail (Thanks, Brad!!):

我问了布拉德·考克斯这个问题,他非常慷慨地给出了详细的回答(谢谢,布拉德!)

I was focused at that time on duplicating as much of Smalltalk as possible in C and doing that as efficiently as possible. Any spare cycles went into making ordinary messaging fast. There was no thought of a specialized messaging option ("reallyFast?" [ bbum: I asked using 'doSomething:withSomething:reallyFast' as the example]) since ordinary messages were already as fast as they could be. This involved hand-tuning the assembler output of the C proto-messager, which was such a portability nightmare that some if not all of that was later taken out. I do recall the hand-hacked messager was very fast; about the cost of two function calls; one to get into the messager logic and the rest for doing method lookups once there.
Static typing enhancements were later added on top of Smalltalk's pure dynamic typing by Steve Naroff and others. I had only limited involvement in that.

当时我专注于在C语言中尽可能多地复制Smalltalk,并尽可能高效地完成它。任何多余的周期都使普通的消息传递变得很快。没有人想到专门的消息传递选项(“真的很快吗?”)(bbum:我问你用‘doSomething:withSomething: withSomething:reallyFast(真的很快)’作为例子),因为普通的信息已经尽可能快了。这涉及到手工调优C proto-messager的汇编器输出,这是一种可移植性的噩梦,有些如果不是全部都被删除了。我记得那个被黑客攻击的信使非常快;关于两个函数调用的成本;一个用于进入messager逻辑,另一个用于进行方法查询。在Steve Naroff等人的Smalltalk纯动态类型之外,还添加了静态类型增强。我只参与了有限的活动。

Go read Brad's answer!

去阅读布拉德的回答!

#3


21  

Just for your information, the runtime doesn't actually care about the selectors, any C string is valid, you could as well make a selector like that: "==+===+---__--¨¨¨¨¨^::::::" with no argument the runtime will accept it, the compiler just can't or else it's impossible to parse. There are absolutely no sanity check when it comes to selectors.

只是为了你的信息,运行时实际上并不关心选择器,任何C字符串是有效的,你可以做这样一个选择:“= = + = = = + - __ -¨¨¨¨¨^::::::”没有参数运行时将接受它,编译器不能,否则很难解析。对于选择器,绝对没有健全的检查。

#4


6  

I assume they are not supported in Objective-C because they weren't available in Smalltalk, either. But that has a different reason than you think: they are not needed. What is needed is support for methods with 0, 1, 2, 3, ... arguments. For every number of arguments, there is already a working syntax to call them. Adding any other syntax would just cause unnecessary confusion.

我认为Objective-C中不支持它们,因为它们在Smalltalk中也没有。但这有一个不同于你所想的原因:它们是不需要的。所需要的是支持0、1、2、3、……参数。对于每一个参数,都有一个可用的语法来调用它们。添加任何其他语法只会导致不必要的混乱。

If you wanted multi-word parameterless selectors, why stop with a single extra word? One might then ask that

如果您想要多字无参数选择器,为什么只需要一个额外的字呢?有人可能会问

 [axolotl perform selector: Y with object: Y]

also becomes supported (i.e. that a selector is a sequence of words, some with colon and a parameter, and others not). While this would have been possible, I assume that nobody considered it worthwhile.

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

#1


109  

This is Brad Cox. My original answer misunderstood the question. I assumed reallyFast was a hardcoded extension to trigger faster messaging, not a kind of syntactic sugar. The real answer is that Smalltalk didn't support it, perhaps because its parser couldn't deal with the (assumed) ambiguity. Although OC's square brackets would remove any ambiguity, I simply didn't think of departing from Smalltalk's keyword structure.

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

#2


42  

21 years of programming Objective-C and this question has never crossed my mind. Given the language design, the compiler is right and the runtime functions are wrong ().

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

The notion of interleaved arguments with method names has always meant that, if there is at least one argument, the last argument is always the last part of the method invocation syntax.

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

Without thinking it through terribly much, I'd bet there are some syntactic bugaboos with not enforcing the current pattern. At the least, it would make the compiler harder to write in that any syntax which has optional elements interleaved with expressions is always harder to parse. There might even be an edge case that flat out prevents it. Certainly, Obj-C++ would make it more challenging, but that wasn't integrated with the language until years after the base syntax was already set in stone.

如果不仔细考虑的话,我敢打赌一定会有一些语法上的麻烦,它们没有执行当前的模式。至少,它会使编译器更难编写,因为任何具有与表达式交叉的可选元素的语法总是更难解析。甚至可能有一种边缘情况可以防止这种情况的发生。当然,object - c++会使它更具有挑战性,但是直到基本语法被设置为石头之后,这才与语言集成。

As far as why Objective-C was designed this way, I'd suspect the answer is that the original designers of the language just didn't consider allowing the interleaved syntax to go beyond that last argument.

至于Objective-C被设计成这样的原因,我想答案是语言最初的设计者并没有考虑允许交叉语法超越最后的论点。

That is a best guess. I'll ask one of 'em and update my answer when I find out more.

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


I asked Brad Cox about this and he was very generous in responding in detail (Thanks, Brad!!):

我问了布拉德·考克斯这个问题,他非常慷慨地给出了详细的回答(谢谢,布拉德!)

I was focused at that time on duplicating as much of Smalltalk as possible in C and doing that as efficiently as possible. Any spare cycles went into making ordinary messaging fast. There was no thought of a specialized messaging option ("reallyFast?" [ bbum: I asked using 'doSomething:withSomething:reallyFast' as the example]) since ordinary messages were already as fast as they could be. This involved hand-tuning the assembler output of the C proto-messager, which was such a portability nightmare that some if not all of that was later taken out. I do recall the hand-hacked messager was very fast; about the cost of two function calls; one to get into the messager logic and the rest for doing method lookups once there.
Static typing enhancements were later added on top of Smalltalk's pure dynamic typing by Steve Naroff and others. I had only limited involvement in that.

当时我专注于在C语言中尽可能多地复制Smalltalk,并尽可能高效地完成它。任何多余的周期都使普通的消息传递变得很快。没有人想到专门的消息传递选项(“真的很快吗?”)(bbum:我问你用‘doSomething:withSomething: withSomething:reallyFast(真的很快)’作为例子),因为普通的信息已经尽可能快了。这涉及到手工调优C proto-messager的汇编器输出,这是一种可移植性的噩梦,有些如果不是全部都被删除了。我记得那个被黑客攻击的信使非常快;关于两个函数调用的成本;一个用于进入messager逻辑,另一个用于进行方法查询。在Steve Naroff等人的Smalltalk纯动态类型之外,还添加了静态类型增强。我只参与了有限的活动。

Go read Brad's answer!

去阅读布拉德的回答!

#3


21  

Just for your information, the runtime doesn't actually care about the selectors, any C string is valid, you could as well make a selector like that: "==+===+---__--¨¨¨¨¨^::::::" with no argument the runtime will accept it, the compiler just can't or else it's impossible to parse. There are absolutely no sanity check when it comes to selectors.

只是为了你的信息,运行时实际上并不关心选择器,任何C字符串是有效的,你可以做这样一个选择:“= = + = = = + - __ -¨¨¨¨¨^::::::”没有参数运行时将接受它,编译器不能,否则很难解析。对于选择器,绝对没有健全的检查。

#4


6  

I assume they are not supported in Objective-C because they weren't available in Smalltalk, either. But that has a different reason than you think: they are not needed. What is needed is support for methods with 0, 1, 2, 3, ... arguments. For every number of arguments, there is already a working syntax to call them. Adding any other syntax would just cause unnecessary confusion.

我认为Objective-C中不支持它们,因为它们在Smalltalk中也没有。但这有一个不同于你所想的原因:它们是不需要的。所需要的是支持0、1、2、3、……参数。对于每一个参数,都有一个可用的语法来调用它们。添加任何其他语法只会导致不必要的混乱。

If you wanted multi-word parameterless selectors, why stop with a single extra word? One might then ask that

如果您想要多字无参数选择器,为什么只需要一个额外的字呢?有人可能会问

 [axolotl perform selector: Y with object: Y]

also becomes supported (i.e. that a selector is a sequence of words, some with colon and a parameter, and others not). While this would have been possible, I assume that nobody considered it worthwhile.

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