Mengapa bagian terakhir dari nama metode Objective-C harus mengambil argumen (bila ada lebih dari satu bagian)?

90

Di Objective-C, Anda tidak bisa mendeklarasikan nama metode di mana komponen terakhir tidak mengambil argumen. Misalnya, berikut ini ilegal.

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

Mengapa Objective-C dirancang seperti ini? Apakah itu hanya artefak Smalltalk yang tidak ada yang melihat perlu disingkirkan?

Batasan ini masuk akal di Smalltalk, karena Smalltalk tidak memiliki pembatas di sekitar pemanggilan pesan, jadi komponen terakhir akan ditafsirkan sebagai pesan unary ke argumen terakhir. Misalnya, BillyAndBobby take:'$100' andRunakan diurai sebagai BillyAndBobby take:('$100' andRun). Ini tidak masalah di Objective-C di mana tanda kurung siku diperlukan.

Komponen pendukung parameterless pemilih tidak akan mendapatkan kita banyak dalam semua cara yang biasa bahasa diukur, sebagai nama sebuah metode programmer picks (misalnya runWith:daripadatake:andRun) tidak mempengaruhi semantik fungsional suatu program, maupun ekspresi bahasa. Memang, program dengan komponen tanpa parameter adalah alfa yang setara dengan program tanpa komponen. Jadi saya tidak tertarik dengan jawaban yang menyatakan bahwa fitur seperti itu tidak diperlukan (kecuali itu adalah alasan yang dinyatakan oleh desainer Objective-C; apakah ada yang kebetulan mengenal Brad Cox atau Tom Love? Apakah mereka ada di sini?) Atau yang mengatakan cara menulis nama metode sehingga fiturnya tidak diperlukan. Manfaat utama adalah keterbacaan dan penulisan (yang seperti keterbacaan, hanya ... Anda tahu), karena itu berarti Anda dapat menulis nama metode yang bahkan lebih mirip dengan kalimat bahasa alami. Yang seperti -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(yang ditunjukkan Matt Gallagher di "Cocoa With Love"-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed, sehingga menempatkan parameter tepat di sebelah kata benda yang sesuai.

Runtime Objective-C Apple (misalnya) sangat mampu menangani pemilih semacam ini, jadi mengapa tidak kompilernya? Mengapa tidak mendukung mereka dalam nama metode juga?

#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
sumber
1
tidak dapat menjelaskan alasan mengapa hal itu tidak mungkin, tetapi mengapa ini mungkin? Apple akan menamai metode tersebut "takeAndRun:" dan "takeAndDontComplain:";)
Atau takeAndRunWith:(id)theMoneydan takeAndDon'tComplainAbout:(id)yourMedicine. Secara tata bahasa canggung, pastinya.
Matthew Frederick
13
Terima kasih telah menanyakan ini - ini adalah pertanyaan yang sangat menarik. Saya akan bertanya-tanya.
bbum
5
Kecanggungan gramatikal yang dipaksakan sesekali membuat saya menginginkan fitur tersebut.
keluar
1
Pertanyaan bagus. Sebagai tambahan, kompilator tidak memiliki masalah dengan metode bernama seperti ini: - (void) :(id)theMoney;atau - (void) :(id)obj1 :(id)obj2;. Jadi penyeleksi hanya terdiri dari titik dua saja. ;-)
Ole Begemann

Jawaban:

111

Ini Brad Cox. Jawaban asli saya salah memahami pertanyaan itu. Saya berasumsi reallyFast adalah ekstensi yang di-hardcode untuk memicu pengiriman pesan yang lebih cepat, bukan semacam gula sintaksis. Jawaban sebenarnya adalah Smalltalk tidak mendukungnya, mungkin karena pengurai tidak dapat menangani ambiguitas (yang diasumsikan). Meskipun tanda kurung siku OC akan menghilangkan ambiguitas, saya sama sekali tidak berpikir untuk berangkat dari struktur kata kunci Smalltalk.

Brad Cox
sumber
Terima kasih, Brad. Interpretasi saya atas jawaban Anda sama; bahwa penyimpangan dari SmallTalk tidak dipertimbangkan.
bbum
42

21 tahun pemrograman Objective-C dan pertanyaan ini tidak pernah terlintas di benak saya. Mengingat desain bahasa, kompilernya benar dan fungsi runtime salah ().

Gagasan argumen berselang-seling dengan nama metode selalu berarti bahwa, jika ada setidaknya satu argumen, argumen terakhir selalu merupakan bagian terakhir dari sintaks pemanggilan metode.

Tanpa terlalu memikirkannya, saya yakin ada beberapa kesalahan sintaksis dengan tidak menerapkan pola saat ini. Paling tidak, ini akan membuat kompiler lebih sulit untuk menulis karena sintaks apapun yang memiliki elemen opsional yang disisipkan dengan ekspresi selalu lebih sulit untuk diurai. Bahkan mungkin ada casing tepi yang mencegahnya rata. Tentu saja, Obj-C ++ akan membuatnya lebih menantang, tetapi itu tidak terintegrasi dengan bahasa sampai bertahun-tahun setelah sintaks dasar sudah ditetapkan.

Sejauh mengapa Objective-C dirancang seperti ini, saya curiga jawabannya adalah bahwa perancang asli bahasa hanya tidak mempertimbangkan untuk membiarkan sintaks yang disisipkan melampaui argumen terakhir itu.

Itu tebakan terbaik. Saya akan bertanya kepada salah satu dari mereka dan memperbarui jawaban saya ketika saya mengetahui lebih lanjut.


Saya bertanya kepada Brad Cox tentang ini dan dia sangat murah hati dalam menanggapi secara detail (Terima kasih, Brad !!):

Saya fokus pada saat itu untuk menduplikasi sebanyak mungkin Smalltalk di C dan melakukannya seefisien mungkin. Setiap siklus cadangan digunakan untuk membuat pengiriman pesan biasa dengan cepat. Tidak ada pemikiran tentang opsi perpesanan khusus ("reallyFast?" [ Bbum: Saya bertanya menggunakan 'doSomething: withSomething: reallyFast' sebagai contoh ]) karena pesan biasa sudah secepat mungkin. Ini melibatkan hand-tuning output assembler dari proto-messager C, yang merupakan mimpi buruk portabilitas sehingga beberapa jika tidak semua itu kemudian dibawa keluar. Saya ingat pesan yang diretas dengan tangan itu sangat cepat; tentang biaya dua pemanggilan fungsi; satu untuk masuk ke logika messager dan sisanya untuk melakukan pencarian metode begitu ada.
Peningkatan pengetikan statis kemudian ditambahkan di atas pengetikan dinamis murni Smalltalk oleh Steve Naroff dan lainnya. Saya hanya terlibat terbatas dalam hal itu.

Bacalah jawaban Brad!

bbum
sumber
Bugaboo sintaks sangat menarik minat saya.
keluar
1
Tampak bagi saya bahwa jika Anda memiliki potongan nama metode tanpa titik dua, Anda memiliki masalah penguraian karena Anda tidak dapat memastikan apakah itu dimaksudkan untuk menjadi bagian dari nama metode atau tidak.
NSResponder
2
Terlintas di benak saya pertama kali saya merancang protokol untuk delegasi yang kurang dari 21 tahun setelah memulai dengan Objective-C. Pola normalnya adalah menyediakan objek yang mengirimkan pesan delegasi sebagai parameter pertama. mis -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Hal ini menyebabkan ketidakkonsistenan yang mencolok dalam nama metode jika Anda memiliki metode dalam protokol yang tidak memerlukan parameter lain. Lihat NSTableViewDataSource sebagai contoh. Satu metode tidak mengikuti pola rapi yang bagus dari semua metode lainnya.
JeremyP
21

Hanya untuk informasi Anda, runtime sebenarnya tidak peduli dengan penyeleksi, string C apa pun valid, Anda juga dapat membuat pemilih seperti itu: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "tanpa argumen runtime akan menerimanya, kompilator tidak bisa atau tidak mungkin untuk mengurai. Sama sekali tidak ada pemeriksaan kewarasan dalam hal penyeleksi.

Psycho
sumber
7
+1 Saya pikir Anda benar-benar gila karena menyarankan ini, tetapi Anda benar. Bagi Anda yang tidak percaya: pastie.org/1388361
Dave DeLong
6

Saya berasumsi mereka tidak didukung di Objective-C karena mereka juga tidak tersedia di Smalltalk. Tetapi itu memiliki alasan yang berbeda dari yang Anda pikirkan: mereka tidak dibutuhkan. Yang dibutuhkan adalah dukungan untuk metode dengan argumen 0, 1, 2, 3, .... Untuk setiap jumlah argumen, sudah ada sintaks yang berfungsi untuk memanggilnya. Menambahkan sintaks lain hanya akan menyebabkan kebingungan yang tidak perlu.

Jika Anda menginginkan pemilih tanpa parameter multi-kata, mengapa berhenti dengan satu kata tambahan? Seseorang mungkin akan menanyakan itu

 [axolotl perform selector: Y with object: Y]

juga menjadi didukung (yaitu selektor adalah urutan kata, beberapa dengan titik dua dan parameter, dan yang lainnya tidak). Meskipun ini mungkin terjadi, saya berasumsi bahwa tidak ada yang menganggapnya bermanfaat.

Martin v. Löwis
sumber
1
Saya telah memikirkan argumen "mereka tidak dibutuhkan", tetapi saya tidak tertarik padanya. Pertanyaan yang diperbarui membuat ini lebih jelas. Mengizinkan komponen pemilih sewenang-wenang untuk tidak mengambil parameter menawarkan lebih sedikit dalam cara penulisan, karena perbedaan antara spasi dan camel case kurang dari perbedaan antara komponen final tanpa parameter dan penulisan ulang pernyataan bahasa alami & parameter reposisi (keduanya harus dilakukan dengan ObjC, sebagaimana adanya).
keluar
Selain itu, mengizinkan komponen tanpa parameter yang berubah-ubah meningkatkan kemungkinan tabrakan kata kunci dan memperumit resolusi nama, terutama saat mencampur C ++ dan ObjC ( anddan orakan menjadi batu sandungan tertentu). Ini akan terjadi jauh lebih sedikit jika hanya komponen akhir dari nama metode yang diizinkan untuk tidak memiliki parameter, karena akan cenderung terdiri dari banyak kata.
keluar