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
)는 프로그램의 기능적 의미 나 언어의 표현성에 영향을주지 않습니다. 실제로, 매개 변수가없는 구성 요소를 가진 프로그램은없는 구성 요소와 알파 동등합니다. 따라서 이러한 기능이 필요하지 않다는 답변에는 관심이 없습니다. 기능이 필요하지 않도록 메서드 이름을 작성하는 방법. 가장 큰 이점은 가독성과 쓰기 능력입니다 (가독성과 비슷합니다. 아시다시피). 자연어 문장과 훨씬 더 유사한 메서드 이름을 작성할 수 있다는 의미입니다. 이의 좋아 -(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;
}
답변
Brad Cox입니다. 내 원래 대답은 질문을 오해했습니다. 나는 reallyFast가 일종의 구문 설탕이 아니라 더 빠른 메시징을 트리거하기 위해 하드 코딩 된 확장이라고 생각했습니다. 진짜 대답은 스몰 토크가 그것을 지원하지 않았다는 것입니다. 아마도 그것의 파서가 모호성을 처리 할 수 없었기 때문일 것입니다. OC의 대괄호가 모호함을 제거 할 것이지만, 저는 단순히 스몰 토크의 키워드 구조에서 벗어나는 것을 생각하지 않았습니다.
답변
21 년 동안 Objective-C를 프로그래밍했고이 질문은 제 마음을 넘어선 적이 없습니다. 언어 디자인을 감안할 때 컴파일러는 옳고 런타임 함수는 잘못되었습니다 ().
메서드 이름이있는 인터리브 인수의 개념은 항상 인수가 하나 이상있는 경우 마지막 인수가 항상 메서드 호출 구문의 마지막 부분임을 의미합니다.
끔찍하게 생각하지 않고 현재 패턴을 적용하지 않는 구문상의 버그가있을 것입니다. 적어도 표현식과 인터리브 된 선택적 요소가있는 구문은 항상 구문 분석하기 가 더 어렵 기 때문에 컴파일러가 작성 하기가 더 어려워집니다. 플랫 아웃이 그것을 방지하는 가장자리 케이스가있을 수도 있습니다. 확실히 Obj-C ++는이를 더 어렵게 만들 것이지만 기본 구문이 이미 결정된 후 몇 년이 지나야 언어와 통합되었습니다.
Objective-C가 이런 방식으로 설계된 이유에 관한 한, 대답은 언어의 원래 디자이너가 인터리브 구문이 마지막 인수를 넘어서는 것을 고려하지 않았다는 것입니다.
그것은 최선의 추측입니다. 나는 그들 중 한 명에게 물어보고 더 많은 것을 알게되면 내 대답을 업데이트 할 것입니다.
나는 브래드 콕스에게 이것에 대해 물었고 그는 세부적으로 답변하는 데 매우 관대했습니다 (감사합니다, 브래드 !!) :
그 당시 저는 가능한 한 많은 스몰 토크를 C로 복제하고 가능한 한 효율적으로하는 데 집중했습니다. 여분의 사이클은 일반적인 메시징을 빠르게 만드는 데 사용되었습니다. 특별한 메시징 옵션 ( “reallyFast?”[ bbum : 예와 같이 ‘doSomething : withSomething : reallyFast’를 사용하여 물었습니다 ]) 에 대한 생각은 없었 습니다. 일반 메시지는 이미 가능한 한 빠르기 때문입니다. 여기에는 C proto-messager의 어셈블러 출력을 수동으로 조정하는 작업이 포함되었습니다.이 작업은 이식성 악몽이되어 일부는 나중에 제거되었습니다. 손으로 해킹 한 메시지가 매우 빠르다는 것을 기억합니다. 두 개의 함수 호출 비용에 대해; 하나는 메시지 로직에 들어가고 나머지는 거기에서 메소드 조회를 수행하기위한 것입니다.
정적 타이핑 향상은 나중에 Steve Naroff와 다른 사람들이 Smalltalk의 순수한 동적 타이핑 위에 추가되었습니다. 나는 그것에 제한적으로 관여했습니다.
브래드의 대답을 읽어보세요!
답변
참고로 런타임은 실제로 선택자에 대해 신경 쓰지 않고 모든 C 문자열이 유효합니다. “== + === + —__– ¨¨¨¨와 같은 선택자를 만들 수 있습니다. ¨ ^ :::::: “인수가없는 경우 런타임은이를 허용합니다. 컴파일러는 허용하지 않거나 구문 분석이 불가능합니다. 선택기에 관해서는 온 전성 검사가 전혀 없습니다.
답변
Objective-C에서는 지원되지 않는다고 가정합니다. 스몰 토크에서도 사용할 수 없었기 때문입니다. 그러나 그것은 당신이 생각하는 것과는 다른 이유가 있습니다. 그들은 필요하지 않습니다. 필요한 것은 0, 1, 2, 3, … 인수가있는 메서드에 대한 지원입니다. 모든 인수에 대해이를 호출하는 작업 구문이 이미 있습니다. 다른 구문을 추가하면 불필요한 혼란이 발생합니다.
여러 단어로 된 매개 변수가없는 선택기를 원했다면 왜 하나의 추가 단어로 중지할까요? 그런 다음 물어볼 수 있습니다
[axolotl perform selector: Y with object: Y]
또한 지원됩니다 (즉, 선택자는 단어 시퀀스이고 일부는 콜론과 매개 변수가 있고 다른 일부는 그렇지 않습니다). 이것이 가능했을지라도 아무도 그것을 가치 있다고 생각하지 않았다고 생각합니다.