Objective-C 메서드 이름의 마지막 부분이 인수를 가져야하는 이유는 무엇입니까 (여러 부분이있는 경우)?


90

Objective-C에서는 마지막 구성 요소가 인수를받지 않는 메서드 이름을 선언 할 수 없습니다. 예를 들어, 다음은 불법입니다.

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

Objective-C가 이런 방식으로 설계된 이유는 무엇입니까? 아무도 제거 할 필요가 없다고 생각한 것은 스몰 토크의 유물 이었습니까?

이 제한은 Smalltalk에서 의미가 있습니다. Smalltalk는 메시지 호출 주위에 구분 기호가 없기 때문에 최종 구성 요소는 마지막 인수에 대한 단항 메시지로 해석됩니다. 예를 들어 BillyAndBobby take:'$100' andRunBillyAndBobby 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;
}

1
불가능한 이유를 설명 할 수 없지만 왜 가능해야합니까? Apple은 메소드 이름을 "takeAndRun :"및 "takeAndDontComplain :"으로 지정합니다.;)

또는 takeAndRunWith:(id)theMoneytakeAndDon'tComplainAbout:(id)yourMedicine. 확실히 문법적으로 어색합니다.
Matthew Frederick

13
질문 해 주셔서 감사합니다. 매우 흥미로운 질문입니다. 주변에 물어 볼게요.
bbum 2010

5
이 기능을 원하게 만드는 것은 때때로 강제 문법적 어색함입니다.
2010

1
좋은 질문입니다. 그냥 옆으로, 컴파일러는 다음과 같이 이름이 방법에 문제가 없습니다 : - (void) :(id)theMoney;- (void) :(id)obj1 :(id)obj2;. 따라서 콜론으로 만 구성된 선택자는 괜찮습니다. ;-)
Ole Begemann

답변:


111

Brad Cox입니다. 내 원래 대답은 질문을 오해했습니다. 나는 reallyFast가 일종의 구문 설탕이 아니라 더 빠른 메시징을 트리거하기 위해 하드 코딩 된 확장이라고 생각했습니다. 진짜 대답은 스몰 토크가 그것을 지원하지 않았다는 것입니다. 아마도 그것의 파서가 모호성을 처리 할 수 ​​없었기 때문일 것입니다. OC의 대괄호가 모호함을 제거 할 것이지만, 저는 단순히 스몰 토크의 키워드 구조에서 벗어나는 것을 생각하지 않았습니다.


고마워, 브래드. 당신의 대답에 대한 나의 해석은 동일했습니다. SmallTalk에서 출발하는 것은 고려되지 않았습니다.
bbum

42

21 년 동안 Objective-C를 프로그래밍했고이 질문은 제 마음을 넘어선 적이 없습니다. 언어 디자인을 감안할 때 컴파일러는 옳고 런타임 함수는 잘못되었습니다 ().

메서드 이름이있는 인터리브 인수의 개념은 항상 인수가 하나 이상있는 경우 마지막 인수가 항상 메서드 호출 구문의 마지막 부분임을 의미합니다.

끔찍하게 생각하지 않고 현재 패턴을 적용하지 않는 구문상의 버그가있을 것입니다. 적어도 표현식과 인터리브 된 선택적 요소가있는 구문은 항상 구문 분석하기 가 더 어렵 기 때문에 컴파일러가 작성 하기가 더 어려워집니다. 플랫 아웃이 그것을 방지하는 가장자리 케이스가있을 수도 있습니다. 확실히 Obj-C ++는이를 더 어렵게 만들 것이지만 기본 구문이 이미 결정된 후 몇 년이 지나야 언어와 통합되었습니다.

Objective-C가 이런 방식으로 설계된 이유에 관한 한, 대답은 언어의 원래 디자이너가 인터리브 구문이 마지막 인수를 넘어서는 것을 고려하지 않았다는 것입니다.

그것은 최선의 추측입니다. 나는 그들 중 한 명에게 물어보고 더 많은 것을 알게되면 내 대답을 업데이트 할 것입니다.


나는 브래드 콕스에게 이것에 대해 물었고 그는 세부적으로 답변하는 데 매우 관대했습니다 (감사합니다, 브래드 !!) :

그 당시 저는 가능한 한 많은 스몰 토크를 C로 복제하고 가능한 한 효율적으로하는 데 집중했습니다. 여분의 사이클은 일반적인 메시징을 빠르게 만드는 데 사용되었습니다. 특별한 메시징 옵션 ( "reallyFast?"[ bbum : 예와 같이 'doSomething : withSomething : reallyFast'를 사용하여 물었습니다 ]) 에 대한 생각은 없었 습니다. 일반 메시지는 이미 가능한 한 빠르기 때문입니다. 여기에는 C proto-messager의 어셈블러 출력을 수동으로 조정하는 작업이 포함되었습니다.이 작업은 이식성 악몽이되어 일부는 나중에 제거되었습니다. 손으로 해킹 한 메시지가 매우 빠르다는 것을 기억합니다. 두 개의 함수 호출 비용에 대해; 하나는 메시지 로직에 들어가고 나머지는 거기에서 메소드 조회를 수행하기위한 것입니다.
정적 타이핑 향상은 나중에 Steve Naroff와 다른 사람들이 Smalltalk의 순수한 동적 타이핑 위에 추가되었습니다. 나는 그것에 제한적으로 관여했습니다.

브래드의 대답을 읽어보세요!


구문 bugaboos는 저에게 매우 관심이 있습니다.
2010

1
콜론이없는 메소드 이름 덩어리가 있다면, 그것이 메소드 이름의 일부인지 아닌지 확신 할 수 없기 때문에 구문 분석 문제가있는 것 같습니다.
NSResponder

2
Objective-C를 시작한 지 21 년이 채 안 된 대의원을위한 프로토콜을 처음으로 디자인했을 때 마음을 사로 잡았습니다. 일반적인 패턴은 델리게이트 메시지를 첫 번째 매개 변수로 보내는 객체를 제공하는 것입니다. 예 : -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. 이로 인해 프로토콜에 다른 매개 변수가 필요하지 않은 메서드가있는 경우 메서드 이름에 불일치가 발생합니다. 예제는 NSTableViewDataSource를 참조하십시오. 한 가지 방법은 다른 모든 방법의 깔끔한 패턴을 따르지 않습니다.
JeremyP 2010

21

참고로 런타임은 실제로 선택자에 대해 신경 쓰지 않고 모든 C 문자열이 유효합니다. "== + === + ---__-- ¨¨¨¨와 같은 선택자를 만들 수 있습니다. ¨ ^ :::::: "인수가없는 경우 런타임은이를 허용합니다. 컴파일러는 허용하지 않거나 구문 분석이 불가능합니다. 선택기에 관해서는 온 전성 검사가 전혀 없습니다.


7
+1 당신이이 제안에 완전히 미쳤다고 생각했지만 당신 말이 맞습니다. 믿지 않는 분들을 위해 : pastie.org/1388361
Dave DeLong

6

Objective-C에서는 지원되지 않는다고 가정합니다. 스몰 토크에서도 사용할 수 없었기 때문입니다. 그러나 그것은 당신이 생각하는 것과는 다른 이유가 있습니다. 그들은 필요하지 않습니다. 필요한 것은 0, 1, 2, 3, ... 인수가있는 메서드에 대한 지원입니다. 모든 인수에 대해이를 호출하는 작업 구문이 이미 있습니다. 다른 구문을 추가하면 불필요한 혼란이 발생합니다.

여러 단어로 된 매개 변수가없는 선택기를 원했다면 왜 하나의 추가 단어로 중지할까요? 그런 다음 물어볼 수 있습니다

 [axolotl perform selector: Y with object: Y]

또한 지원됩니다 (즉, 선택자는 단어 시퀀스이고 일부는 콜론과 매개 변수가 있고 다른 일부는 그렇지 않습니다). 이것이 가능했을지라도 아무도 그것을 가치 있다고 생각하지 않았다고 생각합니다.


1
나는 "그들은 필요하지 않다"라는 주장을 생각했지만 그것에 관심이 없었다. 업데이트 된 질문은이를 더 명확하게합니다. 임의의 선택기 구성 요소가 매개 변수를 사용하지 않도록 허용하면 공백과 낙타 대문자의 차이가 최종, 매개 변수가없는 구성 요소와 자연어 문 다시 작성 및 매개 변수 재배치 (둘 다 수행해야 함) 간의 차이보다 작기 때문에 쓰기 가능성이 적습니다. ObjC와 함께).
outis

또한, 임의의 매개 변수가 구성 요소를 허용하면 C를 혼합 ++ 및 ObjC (특히, 키워드 충돌의 가능성을 제기하고 이름 확인을 복잡하게 and하고 or특정 장애물이 될 것이다). 메서드 이름의 마지막 구성 요소에만 매개 변수가 없도록 허용 된 경우에는 여러 단어로 구성되는 경향이 있으므로 훨씬 덜 발생합니다.
2010
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.