Metaprogramowanie
Metaprogramowanie to technika programowania, w której programy komputerowe mają możliwość traktowania innych programów jako swoich danych. Oznacza to, że program można zaprojektować tak, aby czytał, generował, analizował lub przekształcał inne programy, a nawet sam się modyfikował podczas działania. W niektórych przypadkach pozwala to programistom zminimalizować liczbę wierszy kodu do wyrażenia rozwiązania, co z kolei skraca czas programowania. Pozwala również programom na większą elastyczność w efektywnym radzeniu sobie z nowymi sytuacjami bez ponownej kompilacji.
Metaprogramowanie może służyć do przenoszenia obliczeń z czasu wykonywania do czasu kompilacji , generowania kodu przy użyciu obliczeń czasu kompilacji oraz włączania samomodyfikującego się kodu . Zdolność języka programowania do bycia własnym metajęzykiem nazywana jest refleksją . Refleksja jest cenną cechą języka ułatwiającą metaprogramowanie.
Metaprogramowanie było popularne w latach 70. i 80. przy użyciu języków przetwarzania list, takich jak LISP . Maszyny sprzętowe LISP były popularne w latach 80. XX wieku i umożliwiały aplikacjom przetwarzanie kodu. Były często używane w sztucznej inteligencji .
Podchodzi do
Metaprogramowanie umożliwia programistom pisanie programów i tworzenie kodu, który mieści się w paradygmacie programowania ogólnego . Posiadanie samego języka programowania jako typu danych pierwszej klasy (jak w Lisp , Prolog , SNOBOL lub Rebol ) jest również bardzo przydatne; jest to znane jako homoikoniczność . Programowanie ogólne odwołuje się do funkcji metaprogramowania w języku, umożliwiając pisanie kodu bez konieczności określania typów danych, ponieważ mogą one być dostarczane jako parametry , gdy są używane.
Metaprogramowanie zwykle działa na jeden z trzech sposobów.
- Pierwsze podejście polega na udostępnieniu elementów wewnętrznych aparatu czasu wykonywania do kodu programowania za pośrednictwem interfejsów programowania aplikacji (API), takich jak emiter .NET IL .
- Drugie podejście polega na dynamicznym wykonywaniu wyrażeń, które zawierają polecenia programistyczne, często złożone z łańcuchów znaków, ale mogą też pochodzić z innych metod wykorzystujących argumenty lub kontekst, takich jak JavaScript. Zatem „programy mogą pisać programy”. Chociaż oba podejścia mogą być stosowane w tym samym języku, większość języków skłania się ku jednemu lub drugiemu.
- Trzecie podejście polega na całkowitym wyjściu poza język. Systemy transformacji programów ogólnego przeznaczenia, takie jak kompilatory, które akceptują opisy języków i przeprowadzają dowolne transformacje w tych językach, są bezpośrednimi implementacjami ogólnego metaprogramowania. Pozwala to na zastosowanie metaprogramowania do praktycznie dowolnego języka docelowego, bez względu na to, czy ten język docelowy ma jakiekolwiek własne możliwości metaprogramowania. Można to zobaczyć w pracy ze Scheme i jak pozwala to stawić czoła pewnym ograniczeniom napotykanym w C , używając konstrukcji, które były częścią samego języka Scheme, aby rozszerzyć C.
Lisp jest prawdopodobnie kwintesencją języka z funkcjami metaprogramowania, zarówno ze względu na jego historyczne pierwszeństwo, jak i prostotę i moc jego metaprogramowania. W metaprogramowaniu Lispa operator unquote (zwykle przecinek) wprowadza kod, który jest oceniany w czasie definiowania programu, a nie w czasie wykonywania; zobacz Samoocena formularzy i cytowanie w LISP . Język metaprogramowania jest zatem identyczny z językiem programowania hosta, a istniejące procedury Lisp mogą być bezpośrednio ponownie wykorzystane do metaprogramowania, jeśli jest to pożądane. Podejście to zostało zaimplementowane w innych językach poprzez włączenie do programu interpretera, który pracuje bezpośrednio z danymi programu. Istnieją implementacje tego rodzaju dla niektórych popularnych języków wysokiego poziomu, takich jak RemObjects ' Pascal Script for Object Pascal .
zwyczaje
Generowanie kodu
Prostym przykładem metaprogramu jest ten skrypt powłoki POSIX , który jest przykładem programowania generatywnego :
#!/bin/sh # metaprogram echo '#!/bin/sh' > program dla i w $( seq 992 ) do echo "echo $i " >> program gotowy chmod +x program
Ten skrypt (lub program) generuje nowy program składający się z 993 wierszy, który wypisuje liczby 1–992. To tylko ilustracja tego, jak używać kodu do pisania większej ilości kodu; nie jest to najskuteczniejszy sposób drukowania listy numerów. Niemniej jednak programista może napisać i wykonać ten metaprogram w mniej niż minutę i wygenerować ponad 1000 linii kodu w tym czasie.
Quine to specjalny rodzaj metaprogramu, który na wyjściu tworzy własny kod źródłowy . Quines są na ogół jedynie przedmiotem zainteresowania rekreacyjnego lub teoretycznego.
Nie każde metaprogramowanie obejmuje programowanie generatywne. Jeśli programy można modyfikować w czasie wykonywania lub dostępna jest kompilacja przyrostowa (na przykład w językach C# , Forth , Frink , Groovy , JavaScript , Lisp , Elixir , Lua , Nim , Perl , PHP , Python , REBOL , Ruby , Rust , SAS , Smalltalk , I Tcl ), wówczas można zastosować techniki do wykonywania metaprogramowania bez faktycznego generowania kodu źródłowego.
Jednym ze stylów podejścia generatywnego jest stosowanie języków specyficznych dla domeny (DSL). Dość powszechnym przykładem wykorzystania DSL jest generatywne metaprogramowanie: lex i yacc , dwa narzędzia używane do generowania analizatorów leksykalnych i parserów , pozwalają użytkownikowi opisywać język za pomocą wyrażeń regularnych i gramatyk bezkontekstowych oraz osadzają złożone algorytmy wymagane do efektywnego analizowania język.
Instrumentacja kodu
Jednym z zastosowań metaprogramowania jest instrumentacja programów w celu przeprowadzenia dynamicznej analizy programu .
Wyzwania
Niektórzy twierdzą, że istnieje ostra krzywa uczenia się, aby w pełni wykorzystać funkcje metaprogramowania. Ponieważ metaprogramowanie zapewnia większą elastyczność i konfigurowalność w czasie wykonywania, niewłaściwe użycie lub nieprawidłowe użycie metaprogramowania może spowodować nieuzasadnione i nieoczekiwane błędy, które mogą być niezwykle trudne do debugowania dla przeciętnego programisty. Może wprowadzić ryzyko do systemu i uczynić go bardziej podatnym na ataki, jeśli nie jest używany ostrożnie. Niektóre z typowych problemów, które mogą wystąpić z powodu niewłaściwego użycia metaprogramowania, to niezdolność kompilatora do zidentyfikowania brakujących parametrów konfiguracyjnych, nieprawidłowe lub nieprawidłowe dane mogą skutkować nieznanym wyjątkiem lub różnymi wynikami. Z tego powodu niektórzy uważają, że tylko wysoko wykwalifikowani programiści powinni pracować nad tworzeniem funkcji, które ćwiczą metaprogramowanie w języku lub platformie, a przeciętni programiści muszą nauczyć się korzystać z tych funkcji w ramach konwencji.
Zastosowania w językach programowania
Systemy makro
- Common Lisp i większość dialektów Lisp .
- Schemat makr higienicznych
- MacroML
- Rakieta (język programowania)
- Szablon Haskella
- Makra Scali
- Makra Clojure
- Nim
- Rdza
- Haxe
- Julia
- Eliksir
Asemblery makr
IBM /360 i pochodne miały potężne funkcje asemblera makr , które były często używane do generowania kompletnych programów w języku asemblera [ potrzebne źródło ] lub części programów (na przykład dla różnych systemów operacyjnych). Makra dostarczane z przetwarzania transakcji CICS zawierały makra asemblera, które generowały instrukcje COBOL jako etap przetwarzania wstępnego.
Inne asemblery, takie jak MASM , również obsługują makra.
Metaklasy
Metaklasy są dostarczane przez następujące języki programowania:
Metaprogramowanie szablonów
- C „X Makra”
- Szablony C++
- D
- Common Lisp , Scheme i większość dialektów Lisp przy użyciu operatora quasiquote („backquote”).
- Nim
Etapowe metaprogramowanie
Typy zależne
Użycie typów zależnych pozwala udowodnić, że wygenerowany kod nigdy nie jest niepoprawny. Jednak to podejście jest najnowocześniejsze i rzadko można je znaleźć poza językami programowania badań.
Implementacje
Lista znaczących systemów metaprogramowania jest utrzymywana na liście systemów transformacji programów .
Zobacz też
- Tkacz aspektów
- Porównanie narzędzi do generowania kodu
- Wykonywanie funkcji w czasie kompilacji
- Refleksja w czasie kompilacji
- Programowanie genetyczne
- Homoikonowość
- Programowanie inferencyjne
- Symulator zestawu instrukcji
- Zamierzone programowanie
- Język interpretowany
- Nauczanie maszynowe
- Metakompilator
- Metaobiekt
- Ocena częściowa
- Refleksja (programowanie komputerowe)
- Samodzielny tłumacz
- Samomodyfikujący się kod
- Generowanie kodu źródłowego
- Transkompilator (znany również jako transpilacja)
- Integracja na bardzo dużą skalę
Linki zewnętrzne
- c2.com Wiki: artykuł o metaprogramowaniu
- Metaprogramowanie na Program Transformation Wiki
- Generowanie kodu a metaprogramowanie
- „Solenoid” : Pierwsza platforma metaprogramowania dla eXist-db