Warum muss der letzte Teil eines Objective-C-Methodennamens ein Argument enthalten (wenn mehr als ein Teil vorhanden ist)?

90

In Objective-C können Sie keine Methodennamen deklarieren, bei denen die letzte Komponente kein Argument akzeptiert. Zum Beispiel ist Folgendes illegal.

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

Warum wurde Objective-C so konzipiert? War es nur ein Artefakt von Smalltalk, das niemand für nötig hielt, um es loszuwerden?

Diese Einschränkung ist in Smalltalk sinnvoll, da Smalltalk keine Begrenzer für den Nachrichtenaufruf hat, sodass die letzte Komponente als unäre Nachricht zum letzten Argument interpretiert wird. Zum Beispiel BillyAndBobby take:'$100' andRunwürde analysiert werden als BillyAndBobby take:('$100' andRun). Dies spielt in Objective-C keine Rolle, wo eckige Klammern erforderlich sind.

Die Unterstützung parameterloser Auswahlkomponenten würde uns nicht auf die übliche Weise, wie eine Sprache gemessen wird, viel bringen, wie der Methodenname, den ein Programmierer auswählt (z. B. runWith:anstatttake:andRun) beeinflusst weder die funktionale Semantik eines Programms noch die Ausdruckskraft der Sprache. In der Tat ist ein Programm mit parameterlosen Komponenten Alpha-Äquivalent zu einem ohne. Ich bin daher nicht an Antworten interessiert, die besagen, dass eine solche Funktion nicht erforderlich ist (es sei denn, dies waren die angegebenen Gründe der Objective-C-Designer; kennt jemand Brad Cox oder Tom Love? Sind sie hier?) Oder diese sagen wie man Methodennamen schreibt, damit die Funktion nicht benötigt wird. Der Hauptvorteil ist die Lesbarkeit und Schreibbarkeit (was nur Lesbarkeit entspricht ... Sie wissen), da dies bedeuten würde, dass Sie Methodennamen schreiben könnten, die Sätzen in natürlicher Sprache noch ähnlicher sind. Ähnliches -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(worauf Matt Gallagher in "Cocoa With Love" hinweist-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosedDadurch wird der Parameter unmittelbar neben dem entsprechenden Substantiv platziert.

Die Objective-C-Laufzeit von Apple (zum Beispiel) kann diese Art von Selektoren perfekt verarbeiten. Warum also nicht den Compiler? Warum unterstützen Sie sie nicht auch in Methodennamen?

#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;
}
outis
quelle
1
Ich kann den Grund nicht erklären, warum es nicht möglich ist, aber warum sollte dies möglich sein? Apple würde die Methoden "takeAndRun:" und "takeAndDontComplain:" nennen;)
Oder takeAndRunWith:(id)theMoneyund takeAndDon'tComplainAbout:(id)yourMedicine. Grammatisch umständlich, um sicher zu sein.
Matthew Frederick
13
Vielen Dank, dass Sie dies gestellt haben - es ist eine sehr interessante Frage. Ich werde herumfragen.
bbum
5
Es ist die gelegentliche erzwungene grammatikalische Unbeholfenheit, die mich dazu bringt, die Funktion zu wollen.
Outis
1
Gute Frage. Abgesehen davon hat der Compiler kein Problem mit Methoden wie diesen: - (void) :(id)theMoney;oder - (void) :(id)obj1 :(id)obj2;. Selektoren, die nur aus Doppelpunkten bestehen, sind also in Ordnung. ;-)
Ole Begemann

Antworten:

111

Das ist Brad Cox. Meine ursprüngliche Antwort hat die Frage falsch verstanden. Ich nahm an, dass wirklich Fast eine fest codierte Erweiterung war, um schnelleres Messaging auszulösen, keine Art syntaktischen Zuckers. Die eigentliche Antwort ist, dass Smalltalk es nicht unterstützt hat, vielleicht weil sein Parser die (angenommene) Mehrdeutigkeit nicht bewältigen konnte. Obwohl die eckigen Klammern von OC jede Mehrdeutigkeit beseitigen würden, dachte ich einfach nicht daran, von der Keyword-Struktur von Smalltalk abzuweichen.

Brad Cox
quelle
Danke, Brad. Meine Interpretation Ihrer Antwort war dieselbe; Diese Abweichung von SmallTalk wurde nicht berücksichtigt.
bbum
42

21 Jahre Programmieren von Objective-C und diese Frage ist mir nie in den Sinn gekommen. In Anbetracht des Sprachdesigns ist der Compiler richtig und die Laufzeitfunktionen sind falsch ().

Der Begriff der verschachtelten Argumente mit Methodennamen hat immer bedeutet, dass bei mindestens einem Argument das letzte Argument immer der letzte Teil der Methodenaufrufsyntax ist.

Ohne viel darüber nachzudenken, würde ich wetten, dass es einige syntaktische Bugaboos gibt, bei denen das aktuelle Muster nicht durchgesetzt wird. Zumindest würde es den Compiler schwieriger machen, darin zu schreiben, dass jede Syntax, bei der optionale Elemente mit Ausdrücken verschachtelt sind, immer schwieriger zu analysieren ist. Möglicherweise gibt es sogar einen Randfall, der dies verhindert. Obj-C ++ würde es sicherlich schwieriger machen, aber das wurde erst Jahre, nachdem die Basissyntax bereits in Stein gemeißelt war, in die Sprache integriert.

Was den Grund angeht, warum Objective-C so entworfen wurde, würde ich vermuten, dass die Antwort der ursprünglichen Designer der Sprache einfach nicht in Betracht gezogen hat, die verschachtelte Syntax über dieses letzte Argument hinausgehen zu lassen.

Das ist eine gute Vermutung. Ich werde einen von ihnen fragen und meine Antwort aktualisieren, wenn ich mehr herausfinde.


Ich habe Brad Cox danach gefragt und er hat sehr großzügig im Detail geantwortet (Danke, Brad !!):

Ich habe mich damals darauf konzentriert, so viel Smalltalk wie möglich in C zu duplizieren und dies so effizient wie möglich zu tun. Alle Ersatzzyklen führten dazu, dass normale Nachrichten schnell gesendet wurden. Es wurde nicht an eine spezielle Messaging-Option gedacht ("wirklich schnell?" [ Bbum: Ich habe gefragt, ob ich "doSomething: withSomething: wirklich schnell" als Beispiel verwenden möchte ), da normale Nachrichten bereits so schnell waren, wie sie sein konnten. Dies beinhaltete die manuelle Optimierung der Assembler-Ausgabe des C-Proto-Messagers, was ein solcher Portabilitäts-Albtraum war, dass einige, wenn nicht alle davon später entfernt wurden. Ich erinnere mich, dass der von Hand gehackte Messager sehr schnell war. über die Kosten von zwei Funktionsaufrufen; eine, um in die Messager-Logik einzusteigen, und der Rest, um dort Methodensuchen durchzuführen.
Statische Typisierungsverbesserungen wurden später zusätzlich zu Smalltalks rein dynamischer Typisierung von Steve Naroff und anderen hinzugefügt. Daran war ich nur begrenzt beteiligt.

Lesen Sie Brads Antwort!

bbum
quelle
Syntax-Bugaboos interessieren mich sehr.
Outis
1
Mir scheint, wenn Sie einen Teil des Methodennamens ohne Doppelpunkt hatten, haben Sie ein Analyseproblem, weil Sie nicht sicher sind, ob er Teil des Methodennamens sein soll oder nicht.
NSResponder
2
Es fiel mir ein, als ich zum ersten Mal ein Protokoll für einen Delegierten entwarf, das viel weniger als 21 Jahre nach Beginn von Objective-C lag. Das normale Muster besteht darin, das Objekt, das die Delegatennachricht sendet, als ersten Parameter anzugeben. zB -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Dies führt zu einer störenden Inkonsistenz der Methodennamen, wenn Sie eine Methode im Protokoll haben, die keine anderen Parameter benötigt. Ein Beispiel finden Sie unter NSTableViewDataSource. Eine Methode folgt nicht dem schönen, ordentlichen Muster aller anderen.
JeremyP
21

Nur zu Ihrer Information, die Laufzeit kümmert sich nicht wirklich um die Selektoren, jede C-Zeichenfolge ist gültig, Sie können auch einen Selektor wie diesen erstellen: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "Ohne Argument wird die Laufzeit dies akzeptieren, der Compiler kann es einfach nicht oder es ist unmöglich zu analysieren. Es gibt absolut keine Überprüfung der Gesundheit, wenn es um Selektoren geht.

Psycho
quelle
7
+1 Ich dachte, du wärst total verrückt danach, das vorzuschlagen, aber du hast recht. Für diejenigen unter Ihnen, die nicht glauben: pastie.org/1388361
Dave DeLong
6

Ich gehe davon aus, dass sie in Objective-C nicht unterstützt werden, da sie auch in Smalltalk nicht verfügbar waren. Aber das hat einen anderen Grund als Sie denken: Sie werden nicht benötigt. Was benötigt wird, ist die Unterstützung von Methoden mit 0, 1, 2, 3, ... Argumenten. Für jede Anzahl von Argumenten gibt es bereits eine funktionierende Syntax, um sie aufzurufen. Das Hinzufügen einer anderen Syntax würde nur zu unnötiger Verwirrung führen.

Wenn Sie parametrlose Selektoren mit mehreren Wörtern wollten, warum sollten Sie dann mit einem einzigen zusätzlichen Wort aufhören? Das könnte man dann fragen

 [axolotl perform selector: Y with object: Y]

wird auch unterstützt (dh ein Selektor ist eine Folge von Wörtern, einige mit Doppelpunkt und einem Parameter, andere nicht). Dies wäre zwar möglich gewesen, aber ich gehe davon aus, dass es niemand für lohnenswert hielt.

Martin v. Löwis
quelle
1
Ich hatte an das Argument "Sie werden nicht gebraucht" gedacht, aber ich war nicht daran interessiert. Die aktualisierte Frage macht dies klarer. Das Zulassen, dass beliebige Auswahlkomponenten keine Parameter annehmen, bietet weniger Schreibfähigkeit, da der Unterschied zwischen Leerzeichen und Kamelfall geringer ist als der Unterschied zwischen einer endgültigen, parameterlosen Komponente und dem Umschreiben von Anweisungen in natürlicher Sprache und dem Neupositionieren von Parametern (beides muss durchgeführt werden) mit ObjC, wie es ist).
Outis
Das Zulassen beliebiger parameterloser Komponenten erhöht außerdem die Möglichkeit von Schlüsselwortkollisionen und erschwert die Namensauflösung, insbesondere beim Mischen von C ++ und ObjC ( andund orwäre ein besonderer Stolperstein). Dies würde weitaus weniger passieren, wenn nur die letzte Komponente eines Methodennamens keinen Parameter haben dürfe, da sie in der Regel aus mehreren Wörtern bestehen würde.
Outis