Динамическое связывание кажется ложью

Objective-C использует динамическое связывание: то есть вызовы методов разрешаются во время выполнения.

Отлично.

И использование точечной нотации действительно сводится к вызову метода

Но почему тогда я не могу сделать что-то вроде этого:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


  // Intercept the exception
  @try
  {
    @throw [ NSException 
            exceptionWithName:@"Exception named ME!" 
            reason:@"Because i wanted to" 
            userInfo:nil ] ;
  }
  @catch( id exc ) // pointer to an exception object?
  {



    //NSLog( @"%@ : %@\n", exc.name, exc.reason ) ; // ILLEGAL:  Request for member 
    // 'name' in something not a structure or union..
    // If objective-c uses dynamic binding, and dot notation
    // boils down to calling the getter, then
    // WHY do I have to cast to the concrete type here?

    // Only works if I cast to the concrete type NSException*
    NSException* nexc = (NSException*)exc ;
    NSLog( @"%@ : %@\n", nexc.name, nexc.reason ) ;



  }



  [pool drain];
    return 0;
}

Когда я слышу "динамическое связывание", я думаю, что "он должен вести себя как язык сценариев", и меня удивляет, насколько негибким кажется Objective-C по сравнению с языком сценариев, таким как JavaScript.


person bobobobo    schedule 08.11.2009    source источник
comment
Вы путаете динамическую привязку с тортом. торт - ложь.   -  person Ben James    schedule 08.11.2009
comment
Вызов методов разрешается во время выполнения действительно следует думать, так как отправка сообщений происходит во время выполнения. Использование оператора точки в целом - это скорее взлом, чем что-либо еще.   -  person D.Shawley    schedule 08.11.2009
comment
В этом нет ничего хакерского; это очень хорошо определенный синоним вызова метода с одним дополнительным ограничением, заключающимся в том, что тип должен быть хорошо известен. (Нравится ли кому-то точка или думает, что это хорошее дополнение, полностью зависит от мнения - без комментариев :).   -  person bbum    schedule 08.11.2009
comment
Сказать, что оператор точки не является хакерским, потому что он очень хорошо определен, - все равно что сказать, что триграфы не являются хакерскими, потому что они очень хорошо определены стандартом. Причина (ы), почему вы можете делать [(id)exc name], но не можете (id)exc.name, является одной из причин, почему это хакерство, причем плохое, плохо продуманное. Предоставление более одного способа сделать одно и то же - обычно плохая идея, а тот факт, что эти два способа не являются симметричными, вызывает множество проблем и путаницы.   -  person johne    schedule 08.11.2009


Ответы (3)


Вы путаете среду выполнения и компилятор. Среда выполнения без проблем с этим справляется. Проблема в том, что точечная нотация (которая является синтаксическим сахаром) требует информации о типе для компилятора, чтобы устранить неоднозначность между объектами Objective-C и структурами C.

Если вы не используете точечную нотацию, это работает:

NSLog( @"%@ : %@\n", [exc name], [exc reason]) ;

Вышеупомянутое вызовет предупреждение, если тип не является идентификатором, поскольку компилятор знает, что он знает тип и не может гарантировать, что отправка будет работать, но она будет скомпилирована и запущена.

По сути, проблема заключается в том, что компилятору необходимо знать, следует ли генерировать загрузку структуры или отправку Objective C, другими словами, с точечной нотацией ему необходимо иметь достаточно информации, чтобы определить разницу между объектом и скалярным типом.

person Louis Gerbarg    schedule 08.11.2009

Динамическая привязка не является синонимом динамической типизации. C - это строго типизированный язык, и, в частности, тип аргумента или возвращаемого значения имеет решающее значение и может значительно повлиять на генерацию кода.

Свойства специально разработаны для устранения двусмысленности. В связи с этим было принято решение не разрешать использование синтаксиса точки против id.

В частности, он обращается к этой ситуации:

@interface Foo
- (short) length;
@end

@interface Bar
- (unsigned long long) length;
@end

Учитывая вышеизложенное в двух отдельных файлах заголовков, компиляция [anObject length] выдаст предупреждение, только оба файла заголовков были импортированы. Если был импортирован только один файл заголовка, то сайт вызова будет скомпилирован, возвращая тип, указанный в заголовке. Если бы сайт вызова был для другого метода, был бы возвращен очень неожиданный результат.

Ограничение точечного синтаксиса устраняет эту потенциальную двусмысленность. Это также причина того, почему вы обычно не видите объявления методов со вариантами. C ABI просто не поддерживает это чисто (с учетом сказанного, Objective-C плохо справляется с поддержкой ковариантности типов объектов).

На самом деле разработчики Objective-C редко используют тип id. Объявления конкретных типов позволяют компилятору значительно улучшить проверку кода.

person bbum    schedule 08.11.2009
comment
Как всегда, отличный ответ, Билл! Всегда приятно знать детали дизайнерских решений. И я согласен, я использую id экономно, так как я часто предпочитаю преимущества статической типизации, когда это возможно. - person Quinn Taylor; 10.11.2009

Objective-C поддерживает динамическое связывание. Однако вы не можете использовать свойства для объектов типа id - но вы можете отправлять ему любые сообщения, которые захотите. (Вероятно, это ошибка в текущем определении / реализации ... но пока оставим это в стороне.)

Если бы ты сделал

NSLog(@"%@ : %@", [exc name], [exc reason] ); 

тогда это сработает. Обратите внимание, что вам не нужно помещать новую строку в оператор NSLog, так как все они в любом случае находятся на отдельных строках.

person AlBlue    schedule 08.11.2009
comment
Убедитесь, что вы прочитали ответ bbum. Реализация не ошибка, а намеренно. - person danimal; 08.11.2009
comment
Справедливо, должно быть, ответили примерно в то же время :-) - person AlBlue; 09.11.2009