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

发布于 2024-10-08 10:31:24 字数 2591 浏览 0 评论 0原文

在 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 指出 在“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;
}

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

-(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?

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.

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.

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?

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

野心澎湃 2024-10-15 10:31:24

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

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.

流年已逝 2024-10-15 10:31:24

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

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

没有经过深思熟虑,我敢打赌,存在一些语法错误,不强制执行当前的模式。至少,它会使编译器更难编写,因为任何具有与表达式交错的可选元素的语法总是更难解析。甚至可能存在一种极端情况,完全阻止了它。当然,Obj-C++ 会让它变得更具挑战性,但直到基本语法已经确定多年后才与该语言集成。

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

这是最好的猜测。我会询问其中一位,并在了解更多信息后更新我的答案。


我向布拉德·考克斯询问了此事,他非常慷慨地详细回答了(谢谢布拉德!!):

<罢工>
我当时的注意力集中在
复制尽可能多的 Smalltalk
在 C 中可能并且这样做
尽可能高效。任何备用
周期变得平凡
消息传递速度快。没有想到
专门的消息传递选项
(“reallyFast?” [bbum:我问使用 'doSomething:withSomething:reallyFast'
作为例子
])因为普通
消息已经和它们一样快了
可能是。这涉及到手动调整
C 的汇编输出
原始消息传递器,就是这样一个
便携性噩梦,有些人如果没有
所有这些后来都被删除了。我愿意
还记得那个被人为攻击的消息发送器是
非常快;关于两个人的费用
函数调用;一个进入
消息传递逻辑和其余的事情
方法查找一次。
静态类型增强后来出现了
添加到 Smalltalk 的 pure 之上
Steve Naroff 的动态类型和
其他的。我的参与程度有限
在那。

<罢工>

去阅读布拉德的回答!

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 ().

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.

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.

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.

Go read Brad's answer!

弄潮 2024-10-15 10:31:24

仅供您参考,运行时实际上并不关心选择器,任何 C 字符串都是有效的,您也可以创建这样的选择器:“==+===+---__--¡ ¡^::::::" 如果没有参数,运行时会接受它,但编译器不能接受,否则无法解析。对于选择器来说绝对没有健全性检查。

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.

z祗昰~ 2024-10-15 10:31:24

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

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

 [axolotl perform selector: Y with object: Y]

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

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文