Почему последняя часть имени метода Objective-C должна принимать аргумент (если их больше одной части)?

90

В 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; кто-нибудь знает Брэда Кокса или Тома Лава? Они здесь?) Или что говорят как писать имена методов, чтобы функция не нужна. Основным преимуществом является удобочитаемость и возможность записи (что похоже на читаемость, только ... вы знаете), поскольку это означало бы, что вы могли бы писать имена методов, которые еще больше напоминают предложения естественного языка. Такие, как -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(на что указывает Мэтт Галлахер в "Какао с любовью"-(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;
}
Outis
источник
1
не могу объяснить причину, почему это невозможно, но почему это должно быть возможно? Apple назвала бы методы «takeAndRun:» и «takeAndDontComplain:»;)
Или takeAndRunWith:(id)theMoneyи takeAndDon'tComplainAbout:(id)yourMedicine. Конечно, грамматически неудобно.
Мэтью Фредерик,
13
Спасибо, что задали этот вопрос - это очень интересный вопрос. Я спрошу.
bbum
5
Это случайная вынужденная грамматическая неловкость, которая заставляет меня хотеть эту функцию.
outis
1
Отличный вопрос. Кстати, у компилятора нет проблем с методами, названными так: - (void) :(id)theMoney;или - (void) :(id)obj1 :(id)obj2;. Так что селекторы, состоящие только из двоеточий, подходят. ;-)
Оле Бегеманн

Ответы:

111

Это Брэд Кокс. Мой первоначальный ответ неправильно понял вопрос. Я предположил, что действительноFast - это жестко запрограммированное расширение для ускорения обмена сообщениями, а не синтаксический сахар. Настоящий ответ заключается в том, что Smalltalk не поддерживал его, возможно, потому, что его парсер не мог справиться с (предполагаемой) двусмысленностью. Хотя квадратные скобки OC устраняют любую двусмысленность, я просто не думал об отходе от структуры ключевых слов Smalltalk.

Брэд Кокс
источник
Спасибо, Брэд. Моя интерпретация вашего ответа была такой же; этот отход от SmallTalk не рассматривался.
bbum
42

21 год программирования Objective-C, и этот вопрос никогда не приходил мне в голову. Учитывая дизайн языка, компилятор правильный, а функции времени выполнения - неправильные ().

Понятие чередующихся аргументов с именами методов всегда означало, что, если есть хотя бы один аргумент, последний аргумент всегда является последней частью синтаксиса вызова метода.

Не вдаваясь в подробности, я готов поспорить, что есть некоторые синтаксические ошибки, в которых не применяется текущий шаблон. По крайней мере, это затруднило бы написание компилятора, поскольку любой синтаксис, в котором есть необязательные элементы, чередующиеся с выражениями, всегда труднее анализировать. Может быть, даже крайний корпус, который не позволяет этому. Конечно, Obj-C ++ усложнит задачу, но это не было интегрировано с языком до тех пор, пока не был установлен базовый синтаксис.

Что касается того, почему Objective-C был разработан таким образом, я подозреваю, что ответ заключается в том, что первоначальные разработчики языка просто не рассматривали возможность использования чередующегося синтаксиса за пределами этого последнего аргумента.

Это лучшее предположение. Я спрошу одного из них и обновлю свой ответ, когда узнаю больше.


Я спросил об этом Брэда Кокса, и он очень щедро ответил (Спасибо, Брэд !!):

В то время я был сосредоточен на том, чтобы как можно больше дублировать Smalltalk на C и делать это как можно более эффективно. Любые лишние циклы ушли на ускорение обычного обмена сообщениями. Не было и мысли о специальной опции обмена сообщениями («действительноFast?» [ Bbum: я спросил, используя в качестве примера «doSomething: withSomething: действительноFast» ]), поскольку обычные сообщения уже были настолько быстрыми, насколько могли. Это включало ручную настройку вывода на ассемблере прото-мессенджера C, что было таким кошмаром переносимости, что некоторые, если не все, позже были удалены. Я действительно помню, что взломанный мессенджер был очень быстрым; о стоимости двух вызовов функций; один, чтобы войти в логику мессенджера, а остальные - для поиска методов.
Позднее Стив Нарофф и другие добавили усовершенствования статической типизации поверх чистой динамической типизации Smalltalk. Я имел в этом лишь ограниченное участие.

Иди, прочитай ответ Брэда!

бомж
источник
Ошибки синтаксиса меня очень интересуют.
outis
1
Мне кажется, что если у вас был кусок имени метода без двоеточия, у вас возникла проблема с синтаксическим анализом, потому что вы не могли быть уверены, предназначено ли оно быть частью имени метода или нет.
NSResponder
2
Это пришло мне в голову, когда я впервые разработал протокол для делегата, спустя гораздо меньше 21 года после начала работы с Objective-C. Обычный шаблон - предоставить объект, отправляющий сообщение делегата, в качестве первого параметра. напр -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Это приводит к резкой несогласованности в именах методов, если у вас есть метод в протоколе, которому не нужны другие параметры. См. Пример NSTableViewDataSource. Один метод не следует красивому аккуратному шаблону всех остальных.
JeremyP
21

Просто для вашего сведения, среда выполнения на самом деле не заботится о селекторах, допустима любая строка C, вы также можете создать такой селектор: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "без аргументов среда выполнения примет его, компилятор просто не может, иначе его невозможно проанализировать. Когда дело доходит до селекторов, здесь нет абсолютно никакой проверки.

Психо
источник
7
+1 Я подумал, что ты сошёл с ума, что это предложил, но ты прав. Для тех из вас, кто не верит: pastie.org/1388361
Дэйв Делонг,
6

Я предполагаю, что они не поддерживаются в Objective-C, потому что они также не были доступны в Smalltalk. Но на то есть другая причина, чем вы думаете: они не нужны. Что необходимо, так это поддержка методов с 0, 1, 2, 3, ... аргументами. Для каждого количества аргументов уже существует рабочий синтаксис для их вызова. Добавление любого другого синтаксиса только вызовет ненужную путаницу.

Если вам нужны селекторы без параметров, состоящие из нескольких слов, зачем останавливаться на одном дополнительном слове? Тогда можно спросить, что

 [axolotl perform selector: Y with object: Y]

также становится поддерживаемым (т.е. селектор представляет собой последовательность слов, некоторые из которых имеют двоеточие и параметр, а другие нет). Хотя это было бы возможно, я полагаю, что никто не считал это стоящим.

Мартин против Лёвиса
источник
1
Я думал об аргументе «они не нужны», но меня это не интересовало. Обновленный вопрос проясняет это. Разрешение произвольным компонентам селектора не принимать параметры дает меньше возможностей для записи, поскольку разница между пробелами и верблюжьим регистром меньше, чем разница между окончательным компонентом без параметров и переписыванием операторов естественного языка и параметров изменения положения (оба из которых должны быть выполнены с ObjC, как есть).
outis
Кроме того, разрешение произвольных компонентов без параметров повышает вероятность коллизий ключевых слов и усложняет разрешение имен, особенно при смешивании C ++ и ObjC ( andи это orможет быть определенным камнем преткновения). Это произошло бы гораздо реже, если бы только последний компонент имени метода не имел параметров, так как он обычно состоял бы из нескольких слов.
outis