Dynamiczny język programowania

Z Wikipedii, wolnej encyklopedii
Skocz do: nawigacji, wyszukiwania
Ten artykuł dotyczy klasy języków programowania. Metoda na zmniejszanie złożoności obliczeniowej algorytmów o podobnej nazwie opisana jest w artykule Programowanie dynamiczne.

Dynamiczny język programowania jest terminem powszechnie używanym w informatyce oznaczającym klasę języków programowania wysokiego poziomu, które podczas działania programu wykonują wiele operacji przeprowadzanych w innych językach na etapie kompilacji. Do tych działań zalicza się na przykład rozszerzanie programu przez dodawanie nowego kodu, przez rozszerzanie obiektów i definicji, albo przez zmianę typów danych – wszystko podczas działania programu. Zachowania takie można emulować w niemal wszystkich językach programowania o wystarczającej złożoności, jednak języki dynamiczne mają wbudowane konstrukcje umożliwiające ich bezpośrednie wykorzystanie.

Języki dynamiczne i dynamiczne typowanie nie są tożsamymi pojęciami, a dynamiczny język programowania nie musi zawsze posiadać mechanizmu dynamicznej zmiany typów, chociaż w praktyce wiele z takich języków obsługuje tą właściwość.

Ograniczenia i wieloznaczności definicji[edytuj | edytuj kod]

Definicja języka dynamicznego jest wieloznaczna, ponieważ próbuje się w niej dokonać rozróżnienia na kod i dane, podobnie jak na kompilację i uruchamianie, chociaż pojęcia te nie mają uniwersalnego znaczenia. Maszyny wirtualne, just-in-time compilation i zdolność wielu języków programowania do bezpośrednich modyfikacji kodu maszynowego w niektórych systemach, czynią wspomniane rozróżnienia bardzo abstrakcyjnymi. Na ogólnym poziomie, założenie, że język jest dynamiczny, jest naprawdę założeniem odnośnie łatwego korzystania z dynamicznych mechanizmów, bardziej niż precyzyjnym określeniem możliwości danego języka.

Implementacje[edytuj | edytuj kod]

Istnieje kilka mechanizmów wynikających z koncepcji programowania dynamicznego. Żaden z nich nie może być podstawą do sklasyfikowania języka jako dynamicznego, chociaż większość można znaleźć wśród tych języków.

Eval[edytuj | edytuj kod]

Konstrukcja eval została wprowadzona w języku programowania Lisp i oznaczała ewaluację wyrażenia, czyli proces wykonywania instrukcji umieszczonych w strukturze danych zwanej tam wyrażeniem symbolicznym. Nowe znaczenie tego terminu odnosi się do mechanizmu lub procesu polegającego na wykonywaniu dowolnych instrukcji umieszczonych w łańcuchach tekstowych lub innych danych nie będących kodem maszynowym, do których program ma dostęp. Ewaluacja nowego kodu programu jest częstym zjawiskiem w wielu nowych językach programowania, które w przeciwieństwie do Lispa, nie wymagają od programisty rozróżniania procesu wczytywania łańcucha znaków i przekształcania go do postaci zinternalizowanej w celu wykonania na nim dalszych działań. Języki te to głównie języki interpretowane, gdzie z ewaluacją mamy w gruncie rzeczy do czynienia podczas każdorazowego wczytywania kodu w celu uruchomienia.

Funkcje wyższego rzędu[edytuj | edytuj kod]

Erik Meijer i Peter Drayton zwracają uwagę, że każdy język programowania, w którym możliwe jest ładowanie kodu wykonywalnego podczas pracy programu jest w pewnym sensie zdolny do wykonywania ewaluacji, nawet jeśli kod ten jest w postaci dynamicznie ładowanej biblioteki współdzielonej lub maszynowej formy zrozumiałej przez procesor. Sugerują oni, że tak naprawdę dopiero obecność funkcji wyższego rzędu jest wyznacznikiem pozwalającym nazwać język dynamicznym, a niektóre z języków używają konstrukcji eval tylko jako ubogiej namiastki funkcji wyższego rzędu [1]

Zmiana obiektów podczas pracy[edytuj | edytuj kod]

W języku dynamicznym typy danych lub system obiektów mogą być modyfikowane podczas działania programu. Może to oznaczać tworzenie nowych typów i obiektów o właściwościach wynikających z wyników umieszczonych w programie wyrażeń, albo spowodowanych użyciem domieszek istniejących obiektów i typów. Zmiana obiektów ma również miejsce podczas procesu dziedziczenia lub drzewiastego odwzorowywania typów, czyli zmiany zachowania zdefiniowanych już typów danych (ze szczególnym uwzględnieniem wywoływanych metod).

Programowanie funkcyjne[edytuj | edytuj kod]

Koncepcje znane z programowania funkcyjnego zaimplementowano w wielu dynamicznych językach programowania. One również pochodzą z języka Lisp.

Domknięcia[edytuj | edytuj kod]

Jednym z najpowszechniej używanych konstrukcji programowania funkcyjnego występujących w dynamicznych językach są domknięcia. Umożliwiają one tworzenie nowych instancji funkcji, które jednak nie tracą dostępu do danych kontekstu, w którym zostały utworzone. Prostym przykładem może być stworzenie funkcji służącej do wyszukiwania słowa w tekście:

function nowy_skaner (słowo)
  temp_function = function (wejście)
    szukaj_słowa (wejście, słowo)
  end function
  return temp_function
end function

Zauważ, że wewnętrzna funkcja jest anonimowa (nie ma nazwy), a miejscem jej przechowywania jest zmienna temp_function. Za każdym razem, gdy wywoływana jest funkcja nowy_skaner(), zwracana przez nią będzie nowa funkcja, która pamięta wartość przekazanego jej podczas definiowania argumentu słowo.

Domknięcia[2] są jednym z głównych narzędzi programowania funkcyjnego, a wiele języków obsługuje mechanizmy tego programowania przynajmniej na tym poziomie.

Kontynuacje[edytuj | edytuj kod]

Kolejną cechą niektórych języków dynamicznych jest mechanizm kontynuacji. Konstrukcje kontynuacyjne pozwalają odzwierciedlić stan wykonywania się programu, który może być potem ponownie wywołany. Na przykład parser może zwracać wynik pośredni i kontynuację, która po wywołaniu sprawi, że przetwarzanie danych wejściowych będzie dalej prowadzone. Kontynuacje wpływają na to, jak traktowane są zasięgi zmiennych, funkcji i metod, ze szczególnym naciskiem na tzw. domknięcia. Ich użycie wymaga czujności programisty i ostrożności podczas implementowania przez twórców języka. Z tego powodu wiele języków dynamicznych nie obsługuje kontynuacji.

Mechanizm refleksji[edytuj | edytuj kod]

Refleksja jest cechą wielu dynamicznych języków i zazwyczaj wiąże się z ogólnym procesem analizy typów i metadanych lub polimorfizmem danych. Może ona również oznaczać pełną ewaluację i modyfikację kodu programu reprezentowanego w strukturach danych, tak jak to ma miejsce w wyrażeniach symbolicznych języka Lisp.

Makra[edytuj | edytuj kod]

Pewna ograniczona liczba dynamicznych języków programowania udostępnia mechanizmy, w których ewaluacja i introspekcja kodu łączą się w konstrukcję zwaną makrem. Większość programistów zna ten termin i używało makrodefinicji na przykład w języku C czy C++, gdzie pozwalają one na dokonywanie prostych podstawień łańcuchów stanowiących kod programu. W językach dynamicznych makra umożliwiają dostęp do wewnętrznych struktur kompilatora i pełen dostęp do interpretera, maszyny wirtualnej lub środowiska uruchomieniowego. W ten sposób programista jest w stanie wpływać na procesy związane z optymalizacją kodu i modyfikować składnię i gramatykę używanego języka.

Języki[edytuj | edytuj kod]

Asembler, język C, C++, wczesne wydania Javy, a także FORTRAN nie są językami dynamicznymi.

Przypisy

  1. Meijer, Erik i Peter Drayton: Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages. Microsoft Corporation, 2005.
  2. Obejrzyj przykład użycia na str. 330 książki Larry'ego Walla pt. Programming Perl ISBN 0-596-00027-8

Linki zewnętrzne[edytuj | edytuj kod]