Różnice między wiadomościami a metodami?

13

W Celu C masz pojęcie wysyłania wiadomości do innych obiektów i jest to bardzo podobne do wywoływania metod w językach takich jak C # i Java.

Ale jakie dokładnie są subtelne różnice? Co powinienem myśleć o przesyłaniu wiadomości, myśląc o moim kodzie?

Uwaga: trochę tła tutaj, jestem programistą C # / Java, próbującym zrozumieć niektóre pojęcia dotyczące Celu C.

Vidar
źródło
2
Ponieważ wszystkie są różnymi językami, różnice nie są subtelne. To są różne języki. „gdy myślisz o moim kodzie”? Jaki kod? Myśląc o Javie lub C #, nie myślisz o wiadomościach. Myślisz o metodach. Czy możesz wyjaśnić, w jaki sposób języki niepowiązane z niepowiązanymi pojęciami mogą mieć „subtelne” różnice?
S.Lott,
1
Zadaj pytanie na stackoverflow.com
Amir Rezaei,
1
Czy to pytanie powinno naprawdę dotyczyć StackOverflow? To pytanie o koncepcje programowania, a nie problem z jakimś kodem, który mam. Może się mylę, nie wiem - granice zacierają się ...
Vidar
1
@Vidar, pytanie nie jest subiektywne. Szukasz definicji podręcznika. Programiści bardziej służą opiniom, doświadczeniu i subiektywnym pytaniom.
Stephen Furlani
1
OK - czy istnieje sposób, aby moderator przeniósł to pytanie do StackOverflow?
Vidar

Odpowiedzi:

10

Komunikat to nazwa selektora i parametry tego selektora.

Selektor to symbol.

Metoda jest fragmentem kodu w klasie identyfikowanej przez selektor.

Innymi słowy, [foo bar: baz]mówi „wyślij wiadomość wywoływaną @selector(bar:)z parametrem bazdo obiektu foo. Możesz wysłać tę wiadomość do wielu różnych obiektów.

W przeciwieństwie do tego może wyglądać metoda bar:Foo

-(int)bar:(int)n {
  return n + 1;
}

ale dla pewnej FooTwomoże wyglądać

-(int)bar:(int)n {
  return n + 2;
}

(Mam nadzieję, że mam poprawną składnię; minęło trochę czasu, odkąd ostatnio dotknąłem Celu C).

Kiedy wysyłasz wiadomość, jądro Objective-C wysyła wiadomość, do fooktórej decyduje, czy ją rozumie. Decyduje to na podstawie tego, czy może znaleźć metodę zidentyfikowaną przez ten selektor.

Dwie metody o tej samej nazwie i jedna wiadomość.

Obiekt może również po prostu przesłać określoną wiadomość (lub zestaw wiadomości) do innego obiektu w celu przetworzenia. W takim przypadku wiadomość jest wysyłana do tego obiektu proxy, który nie ma metod dopasowania tej wiadomości , a serwer proxy przesyła wiadomość do zawiniętego obiektu.

Frank Shearar
źródło
więc ... komunikat pojawia się, gdy wywołujesz disinterface (selektor a.invoke, argumenty), a metoda polega na wywołaniu interfejsu (a.methodName)? Czy nie spowodowałoby to, że Java, JavaScript, wszystkie dynamiczne języki mają komunikaty, ponieważ wszystko dzieje się za pośrednictwem podwójnego interfejsu zamiast bezpośrednich skoków i przesunięć w skoki vtable)?
Dmitry
4

Z czysto teoretycznego punktu widzenia nie ma między nimi żadnej różnicy - istnieje wiele formalnych dowodów na to, że oba są całkowicie równoważne i oba mogą być zrealizowane całkowicie pod względem drugiego.

Z nieco mniej teoretycznego punktu widzenia istnieje jedna możliwa różnica: w typowej implementacji wirtualna tablica funkcji jest przydzielana statycznie, a zawartość każdego vtable jest ustalana w czasie kompilacji. Natomiast wyszukiwanie wiadomości odbywa się zwykle za pomocą jakiegoś obiektu podobnego do mapy, który jest zazwyczaj dynamiczny, co oznacza, że ​​można go modyfikować w czasie wykonywania. Dzięki temu stosunkowo łatwo można dodać nową odpowiedź do wiadomości w istniejącej klasie. Niestety w większości przypadków pozostaje to w większości teoretyczne. Po pierwsze, masz do czynienia z kodem samodmodyfikującym, który zdaniem większości osób był długim pomysłemczas temu. Po drugie, aby było to bardzo sensowne, musisz właściwie skompilować nowy kod do istniejącej klasy, aby odpowiedzieć na nową wiadomość, którą wspierasz. Bez tego wszystko, co zyskasz, to możliwość dynamicznego dodawania nowej nazwy dla istniejącej metody.

Jak sugeruje koniec poprzedniego akapitu, z naprawdę praktycznego punktu widzenia różnica między nimi jest bardzo niewielka. Są to po prostu dwa (bardzo nieznacznie) różne sposoby wspierania późnego wiązania. Chociaż wyszukiwanie oparte na wiadomościach jest na ogół nieco wolniejsze, byłoby dość niezwykłe, aby różnica była naprawdę znacząca. Dla większości praktycznych celów są to tylko dwa różne sposoby osiągnięcia tego samego.

Jerry Coffin
źródło
3
Czy masz referencje przedstawiające dowody? Chciałbym rzucić okiem. Istnieje ogromna różnica między wywołaniem metody Java a wysyłaniem wiadomości Smalltalk, nie tylko z powodu późnego wiązania, ale także z powodu oddzielenia nadawcy i odbiorcy: nie można stwierdzić, czy odbiorca wiadomości przetwarza ją, czy przekazuje dalej na przykład.
Frank Shearar,
@FrankShearar: Przepraszam, ale nie. Dowody, które widziałem, zostały wydrukowane, a dawno temu, gdy OOP i metody jego wdrażania były wystarczająco nowe, dowody na takie rzeczy były interesujące dla naukowców.
Jerry Coffin
1

W Celu C wiadomości są opóźnione. Oznacza to, że są one rozwiązywane w czasie wykonywania. C # obsługuje podobną konstrukcję za pomocą słowa kluczowego Dynamic, które deklaruje również, że obiekt jest spóźniony.

Michael Brown
źródło
0

Zwykle wywołania metod są rozwiązywane w czasie kompilacji (chyba że używasz odbicia w Javie), podczas gdy komunikaty w celu C są wysyłane w czasie wykonywania.

Heiko Rupp
źródło
2
Jeśli wywołania metod są rozwiązywane, to czas kompilacji, nie używasz OOP, używasz cukru syntaktycznego dla przeciążonych funkcji przyjmujących structjako pierwszy parametr. Późne wiązanie jest istotną częścią polimorfizmu, a zatem OOP.
2
Tak. Ale nadal możesz kodować wywołanie metody przeciwko czemuś (w Javie), które jest dobrze znane w czasie kompilacji. Wywołanie MyObject.foo () spowoduje błąd, jeśli MyObject lub MyInterface nie ma zdefiniowanej metody foo (). ObjC pozwoli ci wysłać wiadomość „foo”, aby sprzeciwić się MyObject - a jeśli MyObject nie ma „foo”, spowoduje to bombardowanie w czasie wykonywania.
Heiko Rupp
Myślałem, że Cel C był językiem skompilowanym?
Vidar
1
Nie jest to konieczne w przypadku wczesnego / późnego wiązania (pisanie dynamiczne vs. pisanie strukturalne - w twoim przykładzie wywołania metod są sprawdzane podczas kompilacji, ale niekoniecznie wysyłane ). @Vidar: Tak, ale dodaje magii do dynamicznych funkcji. Możesz także skompilować Pythona.
@Vidar: Nie jest to kwestia kompilacji vs. interpretacji, ale raczej statyczności vs. dynamiki. W statycznych językach OOP, takich jak Java, kompilator sprawdza, czy klasa definiuje metodę podczas fazy kompilacji. W dynamicznie pisanym języku, takim jak Objective-C, wiadomości są przekazywane w czasie wykonywania.
mipadi
-1

Wiadomości są obsługiwane przez jądro lub sam język (na przykład w ObjC istnieje bardzo mały kod asemblera, który to robi).

Na przykład w jądrze Linux-a komunikaty są wykonywane przy użyciu wywołań / funkcji systemowych: można o nich dowiedzieć się, szukając programowania w systemie uniksowym.

Podstawowa różnica między wywołaniem metody a komunikatem jest następująca:

  • wywołanie metody występuje tylko w kodzie: w ASM jest tłumaczone przez PUSH przekazanych argumentów.

  • wiadomość jądra jest przeważnie wysyłana do jądra, które jest śledzone i wysyłane z powrotem do określonych procesów. Mogę pomylić je z potokami, ale cokolwiek: wiedz, że istnieją już mechanizmy, które pozwalają na uruchomienie kilku programów jednocześnie i pozwalają na komunikację w tym samym czasie. Oczywiście nie mam nadziei, że będzie to działać w ten sam sposób w systemie Windows lub innym systemie operacyjnym.

żart
źródło
To nie jest „przekazywanie wiadomości”, ponieważ dotyczy języków programowania.
mipadi