Dynamiczny język programowania

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 definicjiEdytuj

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.

ImplementacjeEdytuj

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.

EvalEdytuj

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ęduEdytuj

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 pracyEdytuj

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 funkcyjneEdytuj

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

DomknięciaEdytuj

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.

KontynuacjeEdytuj

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 refleksjiEdytuj

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.

MakraEdytuj

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ęzykiEdytuj

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

PrzypisyEdytuj

  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 PerlISBN 0-596-00027-8

Linki zewnętrzneEdytuj