Późne wiązanie - Late binding


Późne wiązanie , dynamiczne wiązanie lub dynamiczne łączenie — choć nie jest to proces identyczny z dynamicznym łączeniem bibliotek kodu importowanego — to mechanizm programowania komputerowego, w którym metoda wywoływana na obiekcie lub funkcja wywoływana z argumentami jest wyszukiwana według nazwy w czasie wykonywania . Innymi słowy, nazwa jest powiązana z określoną operacją lub obiektem w czasie wykonywania, a nie podczas kompilacji.

W przypadku wczesnego wiązania lub statycznego wiązania w języku obiektowym 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 tego, w przypadku 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.

Główną zaletą korzystania z 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 tablica v klasy może zostać przypadkowo zmodyfikowana. (Nie jest to problem w przypadku platform kompilowanych w trybie just-in-time , takich jak .NET lub Java, ponieważ v-table jest tworzona w czasie wykonywania przez maszynę wirtualną względem bibliotek podczas ich ładowania do uruchomionej aplikacji).

Historia

Termin „późne wiązanie” sięga co najmniej lat sześćdziesiątych, gdzie można go znaleźć w Komunikatach ACM . Termin ten był powszechnie używany do opisywania konwencji wywoływania w językach takich jak Lisp, choć zwykle miał negatywne skojarzenia 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, lokalne przechowywanie, ochronę i ukrywanie procesu stanu oraz ekstremalne późne wiązanie wszystkich rzeczy. Można to zrobić w Smalltalk i LISP. co jest możliwe, ale nie jestem ich świadomy."

Na początku do połowy lat 90. Microsoft mocno 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, z wieloma językami obsługującymi oba na poziomie składni.

W 2000 roku Alex Martelli ukuł termin „ typowanie kaczką ”, aby odnieść się do podobnej koncepcji, ale z innym akcentem. Podczas gdy późne wiązanie generalnie skupia się na szczegółach implementacji, pisanie kaczką skupia się na możliwości ignorowania typów i skoncentrowania się na metodach, które aktualnie posiada obiekt.

Późne implementacje wiążące

Późne wiązanie w dynamicznie typowanych językach obiektowych

W większości języków z typami dynamicznymi listę metod obiektu można zmienić w czasie wykonywania. Wymaga to późnego wiązania.

Późne wiązanie w Lisp

W Lisp . wywołania funkcji globalnych z późnym wiązaniem są efektywnie sprawdzane w czasie wykonywania za pomocą komórki funkcji symbolu . Te powiązania funkcji są zmienne.

Przykład użycia interaktywnej sesji Clozure Common Lisp :

? (defun foo ()
    (bar pi))   ; a still undefined function BAR gets called
;Compiler warnings :
;   In FOO: Undefined function BAR
FOO

? (defun bar (x)   ; now we define it
    (* x 2))
BAR

? (foo)    ; calling foo and it uses the recent definition of BAR
6.283185307179586D0

? (defun bar (x)   ; now we redefine BAR
    (* x 1000))
BAR

? (foo)    ;  FOO now calls the new function, there is no need to recompile/link/load FOO
3141.592653589793D0

? (type-of 'bar)   ;  BAR is a symbol
SYMBOL

? (symbol-function 'bar)  ; the symbol BAR has a function binding
#<Compiled-function BAR #x302000D1B21F>

Późne wiązanie w C++

W C++ późne wiązanie (zwane także „wiązaniem dynamicznym”) odnosi się do tego, co zwykle dzieje się, gdy virtualsłowo kluczowe jest używane w deklaracji metody. C++ tworzy następnie tak zwaną tabelę wirtualną, która jest tabelą przeglądową dla takich funkcji, które będą zawsze sprawdzane podczas ich wywołania. Zwykle termin „późne wiązanie” jest używany na korzyść „ wysyłki dynamicznej ”.

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ładniowe wywoływanie 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 wywołania Invoke.

Późne wiązanie w .NET

W NET, późne wiązanie odnosi się do nadrzędnego się virtualmetody takie jak C ++ lub wdrożenie interfejs. Kompilator tworzy wirtualne tabele dla każdego wywołania metody wirtualnej lub interfejsu, która jest używana w czasie wykonywania do określenia implementacji do wykonania.

Podobnie jak COM i Java, środowisko uruchomieniowe języka wspólnego udostępnia interfejsy API odbicia, które mogą wykonywać wywołania późnego wiązania. Korzystanie z tych połączeń różni się w zależności od języka.

W C# 4 język dodał również pseudotyp „dynamiczny”. Będzie to używane zamiast typu Object, aby wskazać, że pożądane jest późne wiązanie. Wymagany mechanizm późnego wiązania jest określany w czasie wykonywania przy użyciu środowiska uruchomieniowego języka dynamicznego jako punktu początkowego.

Visual Basic używa ich, 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ć wią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 Javy omawiały, w jaki sposób klasy nie były ze sobą połączone w czasie kompilacji. Podczas gdy typy są sprawdzane statycznie w czasie kompilacji, różne implementacje klas mogą zostać zamienione tuż przed środowiskiem wykonawczym, po prostu nadpisując plik klasy. Dopóki nowa definicja klasy będzie miała te same nazwy klas i metod, kod nadal będzie działał. W tym sensie przypomina tradycyjną definicję 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 Javy używanego z metodami wirtualnymi.

Wreszcie, Java może używać późnego wiązania, korzystając z interfejsów API odbić i introspekcji typów, podobnie jak w programowaniu COM i .NET. Ogólnie rzecz biorąc, ci, którzy programują tylko w Javie, nie nazywają tego późnego wiązania. Podobnie użycie technik "kaczki pisania" jest mile widziane w programowaniu Java, z użyciem abstrakcyjnych interfejsów zamiast tego.

Oracle, obecny właściciel Javy, jest znany z używania terminu późne wiązanie w znaczeniu „kaczego pisania” podczas omawiania zarówno Javy, jak i innych języków w tej samej dokumentacji.

Wczesne i późne wiązanie w PL/SQL i Ada

W przypadku korzystania z wczesnego wiązania między Adą a procedurą składowaną w bazie danych sprawdzany jest znacznik czasu, aby sprawdzić, czy procedura składowana nie uległa zmianie od czasu skompilowania kodu. Pozwala to na szybsze wykonywanie i zapobiega uruchamianiu aplikacji w niewłaściwej wersji 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 w przypadku zmiany procedury składowanej.

To rozróżnienie wydaje się być unikalne dla PL/SQL i Ady. Inne języki, które mogą wywoływać procedury PL/SQL, a także inne aparaty baz danych, używają tylko późnego wiązania.

Krytyka

Późne wiązanie ma gorszą wydajność niż wywołanie metody z wczesnym wiązaniem. W większości implementacji poprawny adres metody musi być wyszukiwany według nazwy przy każdym wywołaniu, co wymaga stosunkowo kosztownego przeszukiwania słownika i być może przeciążenia logiki rozwiązywania, jednak na nowoczesnych komputerach jest to generalnie nieistotne.

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 zapobiegać formom analizy statycznej potrzebnej zintegrowanemu środowisku programistycznemu (IDE). Na przykład funkcja „przejdź do definicji” IDE może nie działać w przypadku wywołania z późnym wiązaniem, jeśli IDE nie ma możliwości sprawdzenia, do której klasy może odnosić się wywołanie. Nowoczesne IDE łatwo rozwiązuje ten problem, szczególnie w przypadku języków zorientowanych obiektowo, ponieważ metoda późnego wiązania zawsze określa interfejs lub klasę bazową, w której prowadzi „przejdź do definicji”, a „znajdź wszystkie referencje” można użyć do znalezienia wszystkich implementacji lub nadpisania.

Podobny problem polega na tym, że ewentualny brak informacji o typowaniu może uniemożliwić tworzenie grafów zależności. Jednak inne metody programowania, takie jak abstrakcyjne interfejsy, mogą powodować te same problemy. Nowoczesne IDE może tworzyć takie wykresy zależności równie łatwo, jak obsługuje „znajdź wszystkie referencje”.

Zobacz też

Bibliografia