Późne wiązanie
W informatyce późne wiązanie lub dynamiczne łączenie — chociaż nie jest procesem identycznym z dynamicznym łączeniem importowanych bibliotek kodu — jest mechanizmem programowania komputerowego , w którym metoda wywoływana na obiekcie lub funkcja wywoływana z argumentami jest wyszukiwana według nazwy w czas pracy . Innymi słowy, nazwa jest powiązana z konkretną operacją lub obiektem w czasie wykonywania, a nie podczas kompilacji . Imię wiązanie dynamiczne , ale częściej jest używane w odniesieniu do zakresu dynamicznego .
W przypadku wczesnego wiązania lub wiązania statycznego w języku zorientowanym obiektowo faza kompilacji naprawia wszystkie typy zmiennych i wyrażeń . Jest to zwykle przechowywane w skompilowanym programie jako przesunięcie w wirtualnej tabeli metod („v-table”). W przeciwieństwie do późnego wiązania, kompilator nie odczytuje wystarczającej ilości informacji, aby zweryfikować istnienie metody lub powiązać jej gniazdo w tabeli v. Zamiast tego metoda jest wyszukiwana według nazwy w czasie wykonywania.
Podstawową zaletą używania późnego wiązania w programowaniu Component Object Model (COM) jest to, że nie wymaga od kompilatora odwoływania się do bibliotek zawierających obiekt w czasie kompilacji . Dzięki temu proces kompilacji jest bardziej odporny na konflikty wersji, w których tabela v klasy może zostać przypadkowo zmodyfikowana. (Nie stanowi to problemu w przypadku kompilowanych platform just-in-time, takich jak .NET lub Java , ponieważ tabela v jest tworzona w czasie wykonywania przez maszynę wirtualną względem bibliotek podczas ich ładowania do działającej aplikacji).
Historia
Termin „późne wiązanie” pochodzi co najmniej z lat 60. XX wieku i można go znaleźć w komunikatach ACM . Termin ten był powszechnie używany do opisywania konwencji wywoływania w językach takich jak Lisp, chociaż zwykle miał negatywne konotacje dotyczące wydajności.
W latach 80. Smalltalk spopularyzował programowanie obiektowe (OOP), a wraz z nim późne wiązanie. Alan Kay powiedział kiedyś: „OOP oznacza dla mnie tylko przesyłanie wiadomości, lokalną retencję oraz ochronę i ukrywanie stanu procesu oraz ekstremalnie późne wiązanie wszystkich rzeczy. Można to zrobić w Smalltalk i LISP. Możliwe, że są inne systemy w co jest możliwe, ale nie jestem ich świadomy”.
Od początku do połowy lat 90. Microsoft intensywnie promował swój standard COM jako interfejs binarny między różnymi językami programowania OOP. Programowanie COM w równym stopniu promowało wczesne i późne wiązanie, przy czym wiele języków obsługuje oba na poziomie składni.
W 2000 roku Alex Martelli ukuł termin „ pisanie kaczki ”, aby odnieść się do podobnej koncepcji, ale z innym naciskiem. Podczas gdy późne wiązanie generalnie koncentruje się na szczegółach implementacji, pisanie kaczki koncentruje się na możliwości ignorowania typów i koncentrowania się na metodach, które obecnie posiada obiekt.
Późne wiążące implementacje
Późne wiązanie w dynamicznie typowanych językach obiektowych
W większości języków o dynamicznym typowaniu listę metod obiektu można zmienić w czasie wykonywania. Wymaga to późnego wiązania.
Późne wiązanie w Lispie
W Lispie wywołania funkcji globalnych z późnym wiązaniem są skutecznie wyszukiwane w czasie wykonywania poprzez komórkę funkcyjną symbolu . Te powiązania funkcji są modyfikowalne.
Przykład użycia interaktywnej sesji Clozure Common Lisp :
? ( defun foo () ( bar pi )) ; zostaje wywołana ciągle niezdefiniowana funkcja BAR ;Ostrzeżenia kompilatora : ; W FOO: niezdefiniowana funkcja BAR FOO ? ( defun bar ( x ) ; teraz definiujemy go ( * x 2 )) BAR ? ( foo ) ; dzwoniąc do foo i używa najnowszej definicji BAR 6.283185307179586D0 ? ( nieokreślony pasek
( x ) ; teraz ponownie definiujemy BAR ( * x 1000 )) BAR ? ( foo ) ; FOO wywołuje teraz nową funkcję, nie ma potrzeby ponownej kompilacji/linkowania/ładowania FOO 3141.592653589793D0 ? ( rodzaj 'słupka ') ; BAR jest symbolem SYMBOL ? ( symbol-funkcja 'bar ') ; symbol BAR ma powiązanie funkcji # <Skompilowana funkcja BAR #x302000D1B21F >
Późne wiązanie w C++
W języku C++ późne wiązanie (zwane także „wiązaniem dynamicznym”) odnosi się do tego, co zwykle dzieje się, gdy słowo kluczowe virtual
jest używane w deklaracji metody. Następnie C++ tworzy tak zwaną wirtualną tabelę, która jest tabelą przeglądową dla takich funkcji, z którą zawsze będzie się konsultować, gdy zostaną wywołane. Zwykle termin „późne wiązanie” jest używany na rzecz „ dynamicznej wysyłki ”.
Późne wiązanie w językach COM
W programowaniu COM wywołanie metody z późnym wiązaniem jest wykonywane przy użyciu interfejsu IDispatch . Niektóre języki oparte na modelu COM, takie jak Visual Basic 6, obsługują składnię wywoływania tego interfejsu. Odbywa się to poprzez zdefiniowanie typu zmiennej jako Object. Inne, takie jak C++, wymagają jawnego wywołania GetIDsOfNames w celu wyszukania metody i Invoke w celu jej wywołania.
Późne wiązanie w .NET
W .NET późne wiązanie odnosi się do przesłonięcia metody wirtualnej
, takiej jak C++ lub implementacji interfejsu. Kompilator buduje wirtualne tabele dla każdego wywołania metody wirtualnej lub interfejsu, która jest używana w czasie wykonywania w celu określenia implementacji do wykonania.
Podobnie jak COM i Java, środowisko uruchomieniowe języka wspólnego udostępnia interfejsy API refleksji, które mogą wykonywać późne wywołania wiązania. Korzystanie z tych połączeń różni się w zależności od języka.
W C# 4 język dodał także pseudotyp „dynamiczny”. Zostałoby to użyte zamiast typu Object, aby wskazać, że pożądane jest późne wiązanie. Wymagany konkretny mechanizm późnego wiązania jest określany w czasie wykonywania przy użyciu środowiska wykonawczego języka dynamicznego jako punktu początkowego.
Visual Basic używa ich zawsze, gdy zmienna jest typu Object i obowiązuje dyrektywa kompilatora „Option Strict Off”. Jest to ustawienie domyślne dla nowego projektu VB. Przed wersją 9 tylko obiekty .NET i COM mogły być powiązane z opóźnieniem. W VB 10 zostało to rozszerzone na obiekty oparte na DLR.
Późne wiązanie w Javie
Istnieją trzy definicje późnego wiązania w Javie.
Wczesne dokumenty dotyczące języka Java omawiały, w jaki sposób klasy nie były ze sobą łączone w czasie kompilacji. Podczas gdy typy są sprawdzane statycznie w czasie kompilacji, różne implementacje klas można wymienić tuż przed uruchomieniem, po prostu nadpisując plik klasy. Tak długo, jak nowa definicja klasy miała te same nazwy klas i metod, kod nadal działałby. W tym sensie jest to podobne do tradycyjnej definicji późnego wiązania.
Obecnie popularne jest używanie terminu późne wiązanie w programowaniu Java jako synonimu dynamicznej wysyłki . W szczególności odnosi się to do pojedynczego mechanizmu wysyłania Java używanego z metodami wirtualnymi.
Wreszcie, Java może używać późnego wiązania przy użyciu swoich interfejsów API odbicia i introspekcji typów w taki sam sposób, jak jest to wykonywane w programowaniu COM i .NET. Ogólnie rzecz biorąc, ci, którzy programują tylko w Javie, nie nazywają tego późnym wiązaniem. Podobnie stosowanie technik „kaczego pisania” jest mile widziane w programowaniu Java, zamiast których używane są abstrakcyjne interfejsy.
Firma Oracle, obecny właściciel Javy, była znana z używania terminu późne wiązanie w znaczeniu „pisania na klawiaturze” podczas omawiania zarówno Javy, jak i innych języków w tej samej dokumentacji.
Wczesne vs. późne wiązanie w PL/SQL i Adzie
Podczas korzystania z wczesnego wiązania między Adą a procedurą składowaną w bazie danych sprawdzany jest znacznik czasu w celu sprawdzenia, czy procedura składowana nie uległa zmianie od czasu skompilowania kodu. Pozwala to na szybsze wykonywanie i zapobiega uruchamianiu aplikacji z niewłaściwą wersją procedury składowanej.
W przypadku korzystania z późnego wiązania sprawdzanie znacznika czasu nie jest wykonywane, a procedura składowana jest wykonywana za pośrednictwem anonimowego bloku PL/SQL. Chociaż może to być wolniejsze, eliminuje potrzebę ponownej kompilacji wszystkich aplikacji klienckich po zmianie procedury składowanej.
To rozróżnienie wydaje się być unikalne dla PL/SQL i Ada. Inne języki, które mogą wywoływać procedury PL/SQL, a także inne silniki baz danych, używają tylko późnego wiązania.
Krytyka
Późne wiązanie ma gorszą wydajność niż wczesne wywołanie metody wiązania. W większości implementacji prawidłowy adres metody musi być wyszukiwany według nazwy przy każdym wywołaniu, co wymaga stosunkowo kosztownego przeszukiwania słownika i prawdopodobnie logiki rozwiązywania przeciążeń, ale generalnie jest to pomijalne na nowoczesnych komputerach.
W przypadku niektórych kompilatorów późne wiązanie może uniemożliwić użycie statycznego sprawdzania typu. Podczas wykonywania wywołania z późnym wiązaniem kompilator musi założyć, że metoda istnieje. Oznacza to, że prosty błąd pisowni może spowodować zgłoszenie błędu w czasie wykonywania. Dokładny wyjątek różni się w zależności od języka, ale zwykle nosi nazwę „Nie znaleziono metody” lub „Brak metody”. Nowoczesne kompilatory unikają tego, zapewniając, że każde możliwe wywołanie musi mieć implementację podczas kompilacji.
Późne wiązanie może uniemożliwić formy analizy statycznej wymaganej przez zintegrowane środowisko programistyczne (IDE). Na przykład funkcja „przejdź do definicji” IDE może nie działać w przypadku późnego wywołania, jeśli IDE nie ma możliwości sprawdzenia, do której klasy może odnosić się wywołanie. Nowoczesne IDE z łatwością rozwiązuje ten problem, szczególnie w przypadku języków zorientowanych obiektowo, ponieważ metoda z późnym wiązaniem zawsze określa interfejs lub klasę bazową, do której prowadzi „przejdź do definicji”, a „znajdź wszystkie referencje” można użyć do znalezienia wszystkich implementacji lub zastępuje.
Podobny problem polega na tym, że ewentualny brak wpisania informacji może uniemożliwić utworzenie wykresów zależności. Jednak inne metody programowania, takie jak interfejsy abstrakcyjne, mogą powodować te same problemy. Nowoczesne IDE może tworzyć takie wykresy zależności równie łatwo, jak obsługuje „znajdź wszystkie odniesienia”.