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デザイナーの理由が記載されていない限り、誰かがたまたま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;
}
_
ブラッド・コックスです。私の最初の答えはその質問を誤解していた。 reallyFastは、高速なメッセージングをトリガーするハードコードされた拡張機能であり、一種の構文上の砂糖ではないと想定しました。本当の答えは、Smalltalkはそれをサポートしなかったということです。おそらくそのパーサーが(想定された)あいまいさを処理できなかったためでしょう。 OCの角かっこはあいまいさを取り除きますが、Smalltalkのキーワード構造から逸脱することは考えていませんでした。
21年間Objective-Cをプログラミングしていて、この質問は私の心を超えたことはありません。言語設計を考えると、コンパイラは正しく、ランタイム関数は間違っています()。
インターリーブされた引数とメソッド名の概念は常に、少なくとも1つの引数がある場合、最後の引数は常にメソッド呼び出し構文の最後の部分であることを意味します。
ひどく熟考せずに、現在のパターンを強制しない構文のブガブーがあると思います。少なくとも、オプションの要素が式でインターリーブされている構文は、常にalways解析するのが難しいため、コンパイラーの記述が難しくなります。平らにすることでそれを妨げるEdgeケースもあるかもしれません。確かに、Obj-C++はそれをより困難にしますが、基本構文が既に確定されてから何年か経つまで、それは言語に統合されませんでした。
Objective-Cがこのように設計された理由については、言語の元の設計者がインターリーブされた構文がその最後の引数を超えることを許可することを考慮していなかったことが原因だと思います。
それは最良の推測です。そのうちの1つに質問し、詳細がわかったら回答を更新します。
私はこれについてブラッド・コックスに尋ねました、そして彼は詳細に答えるのにとても寛大でした(ありがとう、ブラッド!!):
私は当時、Cで可能な限り多くのSmalltalkを複製し、それを可能な限り効率的に行うことに集中していました。通常のメッセージングを高速化するために、余分なサイクルが発生しました。特別なメッセージングオプション( "reallyFast?" [bbum:例として 'doSomething:withSomething:reallyFast'を例として使用して尋ねた])は考えられませんでした。通常のメッセージはすでに可能な限り高速だったためです。 。これには、Cプロトメッセンジャーのアセンブラー出力を手動で調整する必要がありました。手動でハッキングされたメッセージが非常に高速だったことを思い出します。 2つの関数呼び出しのコストについて。 1つはメッセージャロジックに入り、残りはそこでメソッド検索を実行するためのものです。
Steve Naroff氏などによるSmalltalkの純粋な動的型付けに加えて、静的型付けの機能強化が後に追加されました。私はそれに限られた関与しかありませんでした。
ブラッドの答えを読んでください!
参考までに、ランタイムは実際にはセレクターを気にしません。C文字列はすべて有効です。次のようなセレクターを作成することもできます。 "== + === + ---__--¨¨¨¨ ¨^ :::::: "引数がなければ、ランタイムはそれを受け入れますが、コンパイラーはそれができないか、そうでなければ解析できません。セレクタに関しては、完全性チェックはまったくありません。
Smalltalkでも利用できなかったため、Objective-Cではサポートされていないと思います。しかし、それはあなたが考えるのとは異なる理由があります。それらは必要ではありません。必要なのは、引数が0、1、2、3、...のメソッドのサポートです。引数の数ごとに、それらを呼び出すための構文がすでに機能しています。他の構文を追加すると、不要な混乱が生じるだけです。
マルチワードのパラメーターレスセレクターが必要な場合、なぜ1つの追加のワードで停止するのですか?次に、それを尋ねるかもしれません
[axolotl perform selector: Y with object: Y]
もサポートされるようになります(つまり、セレクターは単語のシーケンスであり、一部にはコロンとパラメーターがあり、その他はそうではありません)。これは可能だったでしょうが、私はそれを価値があると誰も考えていなかったと思います。