Tại sao phần cuối cùng của tên phương thức Objective-C phải có đối số (khi có nhiều hơn một phần)?


90

Trong Objective-C, bạn không thể khai báo tên phương thức trong đó thành phần cuối cùng không nhận đối số. Ví dụ, sau đây là bất hợp pháp.

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

Tại sao Objective-C lại được thiết kế theo cách này? Nó chỉ là một đồ tạo tác của Smalltalk mà không ai thấy cần phải loại bỏ?

Hạn chế này có ý nghĩa trong Smalltalk, vì Smalltalk không có các dấu phân cách xung quanh lệnh gọi thông báo, vì vậy thành phần cuối cùng sẽ được hiểu là một thông báo một ngôi cho đối số cuối cùng. Ví dụ, BillyAndBobby take:'$100' andRunsẽ được phân tích cú pháp là BillyAndBobby take:('$100' andRun). Điều này không quan trọng trong Objective-C, nơi bắt buộc phải có dấu ngoặc vuông.

Hỗ trợ các thành phần bộ chọn không tham số sẽ không giúp ích cho chúng tôi nhiều theo tất cả các cách thông thường mà một ngôn ngữ được đo lường, như tên phương thức mà lập trình viên chọn (ví dụ: runWith:thay vìtake:andRun) không ảnh hưởng đến ngữ nghĩa chức năng của một chương trình, cũng như tính biểu cảm của ngôn ngữ. Thật vậy, một chương trình có các thành phần không có tham số là alpha tương đương với một chương trình không có. Vì vậy, tôi không quan tâm đến những câu trả lời rằng một tính năng như vậy là không cần thiết (trừ khi đó là lý do đã nêu của các nhà thiết kế Objective-C; có ai tình cờ biết Brad Cox hoặc Tom Love không? Họ có ở đây không?) Hoặc nói rằng cách viết tên phương thức để tính năng không cần thiết. Lợi ích chính là khả năng đọc và khả năng ghi (giống như khả năng đọc, chỉ ... bạn biết), vì nó có nghĩa là bạn có thể viết các tên phương thức thậm chí gần giống với các câu ngôn ngữ tự nhiên hơn. Những thứ thích -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(mà Matt Gallagher chỉ ra trong "Cocoa With Love"-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed, do đó đặt tham số ngay bên cạnh danh từ thích hợp.

Thời gian chạy Objective-C của Apple (ví dụ) hoàn toàn có khả năng xử lý các loại bộ chọn này, vậy tại sao không phải là trình biên dịch? Tại sao không hỗ trợ chúng trong tên phương thứ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
không thể giải thích lý do tại sao nó không thể, nhưng tại sao điều này phải có thể? Apple sẽ đặt tên cho phương pháp "takeAndRun:" và "takeAndDontComplain:";)

Hoặc takeAndRunWith:(id)theMoneytakeAndDon'tComplainAbout:(id)yourMedicine. Chắc chắn là khó hiểu về mặt ngữ pháp.
Matthew Frederick

13
Cảm ơn vì đã hỏi điều này - đó là một câu hỏi rất thú vị. Tôi sẽ hỏi xung quanh.
bbum

5
Đó là sự lúng túng ngữ pháp đôi khi bị ép buộc khiến tôi muốn tính năng này.
outis

1
Câu hỏi tuyệt vời. Ngoài ra, trình biên dịch không có vấn đề gì với các phương thức có tên như sau: - (void) :(id)theMoney;hoặc - (void) :(id)obj1 :(id)obj2;. Vì vậy, bộ chọn không bao gồm gì ngoài dấu hai chấm là tốt. ;-)
Ole Begemann

Câu trả lời:


111

Đây là Brad Cox. Câu trả lời ban đầu của tôi đã hiểu sai câu hỏi. Tôi cho rằng thực sựFast là một phần mở rộng được mã hóa cứng để kích hoạt nhắn tin nhanh hơn, không phải là một loại đường cú pháp. Câu trả lời thực sự là Smalltalk không hỗ trợ nó, có lẽ bởi vì trình phân tích cú pháp của nó không thể giải quyết sự mơ hồ (giả định). Mặc dù dấu ngoặc vuông của OC sẽ loại bỏ bất kỳ sự mơ hồ nào, tôi chỉ đơn giản là không nghĩ đến việc rời khỏi cấu trúc từ khóa của Smalltalk.


Cảm ơn, Brad. Cách giải thích của tôi về câu trả lời của bạn giống nhau; việc rời khỏi SmallTalk không được xem xét.
bbum

42

21 năm lập trình Objective-C và câu hỏi này chưa bao giờ xuất hiện trong đầu tôi. Với thiết kế ngôn ngữ, trình biên dịch là đúng và các hàm thời gian chạy là sai ().

Khái niệm về các đối số xen kẽ với tên phương thức luôn có nghĩa rằng, nếu có ít nhất một đối số, thì đối số cuối cùng luôn là phần cuối cùng của cú pháp gọi phương thức.

Không cần suy nghĩ nhiều về nó, tôi cá rằng có một số bugaboo cú pháp không thực thi mô hình hiện tại. Ít nhất, nó sẽ khiến trình biên dịch khó viết hơn trong đó bất kỳ cú pháp nào có các phần tử tùy chọn xen kẽ với các biểu thức luôn khó phân tích cú pháp hơn. Thậm chí có thể có một trường hợp cạnh phẳng ngăn cản nó. Chắc chắn, Obj-C ++ sẽ khiến nó trở nên khó khăn hơn, nhưng điều đó không được tích hợp với ngôn ngữ này cho đến nhiều năm sau khi cú pháp cơ sở đã được thiết lập sẵn.

Đối với lý do tại sao Objective-C được thiết kế theo cách này, tôi nghi ngờ câu trả lời là các nhà thiết kế ban đầu của ngôn ngữ này đã không xem xét việc cho phép cú pháp xen kẽ vượt ra ngoài đối số cuối cùng đó.

Đó là một dự đoán tốt nhất. Tôi sẽ hỏi một trong số họ và cập nhật câu trả lời của tôi khi tôi tìm hiểu thêm.


Tôi đã hỏi Brad Cox về điều này và anh ấy rất hào phóng trả lời chi tiết (Cảm ơn, Brad !!):

Vào thời điểm đó, tôi đã tập trung vào việc sao chép càng nhiều Smalltalk càng tốt trong C và làm điều đó hiệu quả nhất có thể. Mọi chu kỳ rảnh rỗi đều giúp cho việc nhắn tin thông thường trở nên nhanh chóng. Không có suy nghĩ về một tùy chọn nhắn tin chuyên biệt ("thật nhanh?" [ Bbum: Tôi đã hỏi bằng cách sử dụng 'doSomething: withSomething: reallyFast' làm ví dụ ]) vì các tin nhắn thông thường đã nhanh như chúng có thể. Điều này liên quan đến việc điều chỉnh thủ công đầu ra của trình lắp ráp của C proto-messager, đó là một cơn ác mộng về tính di động đến nỗi một số nếu không muốn nói là tất cả sau này đã bị loại bỏ. Tôi nhớ lại tin nhắn bị tấn công rất nhanh; về chi phí của hai lần gọi hàm; một để tìm hiểu logic của máy nhắn tin và phần còn lại để thực hiện tra cứu phương pháp khi ở đó.
Các cải tiến về tính năng gõ tĩnh sau đó đã được Steve Naroff và những người khác thêm vào tính năng gõ động thuần túy của Smalltalk. Tôi chỉ tham gia hạn chế vào việc đó.

Hãy đọc câu trả lời của Brad!


Cú pháp bugaboos làm tôi rất quan tâm.
outis

1
Có vẻ như đối với tôi rằng nếu bạn có một đoạn tên phương thức không có dấu hai chấm, bạn đã gặp vấn đề phân tích cú pháp vì bạn không thể chắc chắn liệu nó có phải là một phần của tên phương thức hay không.
NSResponder

2
Tôi đã nghĩ ngay đến lần đầu tiên tôi thiết kế một giao thức cho một đại biểu chưa đầy 21 năm sau khi bắt đầu với Objective-C. Mẫu thông thường là cung cấp đối tượng gửi thông điệp ủy nhiệm làm tham số đầu tiên. vd -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Điều này dẫn đến sự mâu thuẫn khó hiểu trong tên phương thức nếu bạn có một phương thức trong giao thức không cần tham số nào khác. Xem NSTableViewDataSource để làm ví dụ. Một phương pháp không tuân theo khuôn mẫu gọn gàng đẹp đẽ của tất cả các phương pháp khác.
JeremyP

21

Chỉ đối với thông tin của bạn, thời gian chạy thực sự không quan tâm đến các bộ chọn, bất kỳ chuỗi C nào đều hợp lệ, bạn cũng có thể tạo một bộ chọn như vậy: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "không có đối số thời gian chạy sẽ chấp nhận nó, trình biên dịch không thể hoặc nếu không thì không thể phân tích cú pháp. Hoàn toàn không có kiểm tra tỉnh táo khi nói đến các bộ chọn.


7
+1 Tôi nghĩ rằng bạn hoàn toàn điên rồ khi đề xuất điều này, nhưng bạn đã đúng. Dành cho những ai không tin: pastie.org/1388361
Dave DeLong

6

Tôi cho rằng chúng không được hỗ trợ trong Objective-C vì chúng cũng không có sẵn trong Smalltalk. Nhưng điều đó có lý do khác với bạn nghĩ: chúng không cần thiết. Điều cần thiết là hỗ trợ các phương thức có đối số 0, 1, 2, 3, .... Đối với mỗi số đối số, đã có một cú pháp hoạt động để gọi chúng. Thêm bất kỳ cú pháp nào khác sẽ chỉ gây ra sự nhầm lẫn không cần thiết.

Nếu bạn muốn bộ chọn không tham số nhiều từ, tại sao lại dừng lại với một từ bổ sung? Sau đó người ta có thể hỏi rằng

 [axolotl perform selector: Y with object: Y]

cũng trở nên được hỗ trợ (nghĩa là một bộ chọn là một chuỗi các từ, một số có dấu hai chấm và một tham số, còn một số khác thì không). Mặc dù điều này có thể xảy ra, nhưng tôi cho rằng không ai coi nó là đáng giá.


1
Tôi đã nghĩ đến lập luận "chúng không cần thiết", nhưng tôi không quan tâm đến nó. Câu hỏi cập nhật làm cho điều này rõ ràng hơn. Việc cho phép các thành phần bộ chọn tùy ý không lấy tham số cung cấp ít hơn về khả năng ghi, vì sự khác biệt giữa dấu cách và chữ hoa camel nhỏ hơn sự khác biệt giữa thành phần cuối cùng, không có tham số và việc viết lại các câu lệnh ngôn ngữ tự nhiên và các tham số định vị lại (cả hai đều phải được thực hiện với ObjC, như nó vốn có).
outis

Ngoài ra, việc cho phép các thành phần không tham số tùy ý làm tăng khả năng xung đột từ khóa và làm phức tạp việc phân giải tên, đặc biệt là khi trộn C ++ và ObjC ( andorsẽ là những trở ngại cụ thể). Điều này sẽ ít xảy ra hơn nếu chỉ cho phép thành phần cuối cùng của tên phương thức không có tham số, vì nó sẽ có xu hướng bao gồm nhiều từ.
outis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.