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


90

У Objective-C ви не можете оголосити імена методів, коли останній компонент не бере аргумент. Наприклад, наступне є незаконним.

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

Чому Objective-C був розроблений саме таким чином? Це був лише артефакт Смолталка, від якого ніхто не бачив необхідності позбавлятися?

Це обмеження має сенс у 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;
}

1
не можу пояснити причину, чому це неможливо, але чому це повинно бути можливим? Apple назвала б методи "takeAndRun:" та "takeAndDontComplain:";)

Або takeAndRunWith:(id)theMoneyі takeAndDon'tComplainAbout:(id)yourMedicine. Напевно, граматично незграбний.
Matthew Frederick

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 і робити це якомога ефективніше. Будь-які запасні цикли використовувались для швидкого створення звичайних повідомлень. Не було жодної думки про спеціалізований варіант обміну повідомленнями ("reallyFast?" [ Bbum: Я запитав, використовуючи 'doSomething: withSomething: reallyFast' як приклад ]), оскільки звичайні повідомлення вже були настільки швидкими, наскільки могли бути. Це передбачало ручну настройку вихідних даних асемблера протоколу обміну повідомленнями C, що було таким кошмаром для перенесення, що пізніше було знято деякі, якщо не все. Я пам’ятаю, що ручний злом повідомлень був дуже швидким; про вартість двох викликів функції; один, щоб потрапити в логіку обміну повідомленнями, а решта - для того, щоб зробити там пошук методів.
Пізніше вдосконалення статичного набору тексту були додані до чистого динамічного набору тексту Smalltalk Стівом Нароффом та іншими. Я мав лише обмежену участь у цьому.

Прочитайте відповідь Бреда!


Синтаксис bugaboos мене дуже цікавить.
outis

1
Мені здається, що якщо у вас був шматок імені методу без двокрапки, у вас є проблема синтаксичного аналізу, оскільки ви не можете бути впевнені, чи передбачається вона бути частиною імені методу чи ні.
NSResponder

2
Це мені спало на думку, коли я вперше розробив протокол для делегата, який пройшов значно менше 21 року після початку роботи з Objective-C. Звичайним шаблоном є подання об'єкта, що відправляє повідомлення делегата, як першого параметра. напр -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Це призводить до невідповідності в іменах методів, якщо у вас є метод у протоколі, який не потребує інших параметрів. Див. Приклад NSTableViewDataSource. Один із методів не відповідає приємному акуратному малюнку всіх інших.
JeremyP

21

Тільки для вашої інформації, час виконання насправді не турбується про селектори, будь-який рядок C є дійсним, ви також можете зробити такий селектор: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "без аргументу середовище виконання прийме його, компілятор просто не може, або неможливо проаналізувати. Що стосується селекторів, немає абсолютно жодної перевірки осудності.


7
+1 Я думав, що ти був абсолютно божевільний, коли ти це запропонував, але ти маєш рацію. Для тих, хто не вірить: pastie.org/1388361
Dave

6

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

Якщо ви хотіли багатословні селектори без параметрів, навіщо зупинятися на одному зайвому слові? Тоді можна про це запитати

 [axolotl perform selector: Y with object: Y]

також стає підтримуваним (тобто, що селектор - це послідовність слів, деякі з двокрапкою та параметром, а інші ні). Хоча це було б можливо, я припускаю, що ніхто не вважав цього вартим уваги.


1
Я думав про аргумент "вони не потрібні", але він мене не цікавив. Оновлене запитання робить це зрозумілішим. Дозвіл довільним компонентам селектора не приймати параметри забезпечує меншу зручність запису, оскільки різниця між пробілами та випадком верблюда менша, ніж різниця між кінцевим компонентом без параметрів та переписуванням висловлювань на природній мові та перестановкою параметрів (обидва повинні бути виконані з ObjC, як це є).
outis

Крім того, дозволяючи довільні безпараметричні компоненти, виникає можливість зіткнень ключових слів та ускладнює роздільну здатність імен, особливо при змішуванні C ++ та ObjC ( andі це orможе бути особливим каменем спотикання). Це сталося б набагато менше, якби лише кінцевий компонент імені методу не мав параметра, оскільки він, як правило, складався з декількох слів.
outis
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.