Metaprogramowanie - Metaprogramming

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 odczytywał, generował, analizował lub przekształcał inne programy, a nawet sam się modyfikował podczas działania. W niektórych przypadkach pozwala to programistom zminimalizować liczbę linii kodu do wyrażenia rozwiązania, co z kolei skraca czas programowania. Pozwala również programom na większą elastyczność, aby skutecznie radzić sobie z nowymi sytuacjami bez ponownej kompilacji.

Metaprogramming mogą być używane do przenoszenia obliczeń z run-time do czasu kompilacji , aby wygenerować kod za pomocą obliczeń w czasie kompilacji, oraz umożliwić self-modyfikacji kodu . Zdolność języka programowania do bycia własnym metajęzykiem nazywana jest refleksją . Odbicie to cenna funkcja języka ułatwiająca 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. i umożliwiały aplikacjom przetwarzającym kod. Były często wykorzystywane do zastosowań sztucznej inteligencji .

Podejścia

Metaprogramowanie umożliwia programistom pisanie programów i tworzenie kodu, który mieści się w ogólnym paradygmacie programowania . Posiadanie samego języka programowania jako pierwszorzędnego typu danych (jak w Lisp , Prolog , SNOBOL , czy Rebol ) jest również bardzo przydatne; jest to znane jako homoikoniczność . Programowanie generyczne wywołuje funkcję 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 zazwyczaj działa na jeden z trzech sposobów.

  1. Pierwsze podejście polega na uwidocznieniu elementów wewnętrznych aparatu czasu wykonywania w kodzie programistycznym za pomocą interfejsów programowania aplikacji (API), takich jak emiter .NET IL .
  2. Drugie podejście to dynamiczne wykonywanie wyrażeń, które zawierają polecenia programistyczne, często złożone z ciągów znaków, ale mogą również pochodzić z innych metod używających argumentów lub kontekstu, takich jak JavaScript. Tak więc „programy mogą pisać programy”. Chociaż oba podejścia mogą być używane w tym samym języku, większość języków ma tendencję do skłaniania się ku jednemu lub drugiemu.
  3. Trzecie podejście to całkowite wyjście 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 własne możliwości metaprogramowania. Widać to w pracy z Scheme i jak pozwala na pokonanie pewnych ograniczeń napotykanych w C poprzez użycie konstrukcji, które były częścią samego języka Scheme, aby rozszerzyć C.

Lisp jest prawdopodobnie kwintesencją języka z możliwościami metaprogramowania, zarówno ze względu na swój historyczny precedens, jak i ze względu na prostotę i moc metaprogramowania. W metaprogramowaniu w Lispie operator unquote (zazwyczaj przecinek) wprowadza kod, który jest oceniany w czasie definicji programu, a nie w czasie wykonywania; zobacz Formularze samooceny 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 użyte do metaprogramowania, jeśli jest to pożądane. To podejście 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 .

Zastosowania

Generowanie kodu

Prostym przykładem metaprogramu jest skrypt POSIX Shell , który jest przykładem programowania generatywnego :

#!/bin/sh
# metaprogram
echo '#!/bin/sh' > program
for i in $(seq 992)
do
    echo "echo $i" >> program
done
chmod +x program

Ten skrypt (lub program) generuje nowy 993-wierszowy program, który wyświetla liczby 1–992. To tylko ilustracja, jak używać kodu do pisania większej ilości kodu; nie jest to najskuteczniejszy sposób na wydrukowanie listy liczb. Niemniej jednak programista może napisać i wykonać ten metaprogram w mniej niż minutę iw tym czasie wygeneruje ponad 1000 linii kodu.

Quine jest szczególnym rodzajem metaprogram że produkuje własne kodu źródłowego jako wyjście. Quines mają na ogół jedynie znaczenie rekreacyjne lub teoretyczne.

Nie każde metaprogramowanie obejmuje programowanie generatywne. Czy programy można modyfikować w czasie wykonywania lub czy dostępna jest kompilacja przyrostowa (na przykład w C# , Forth , Frink , Groovy , JavaScript , Lisp , Elixir , Lua , Nim , Perl , PHP , Python , REBOL , Ruby , Rust , SAS , Smalltalk , i Tcl ), to techniki mogą być wykorzystywane 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 użycia DSL jest metaprogramowanie generatywne: lex i yacc , dwa narzędzia używane do generowania analizatorów i parserów leksykalnych , pozwalają użytkownikowi opisać język za pomocą wyrażeń regularnych i gramatyk bezkontekstowych oraz osadzić złożone algorytmy wymagane do efektywnego parsowania język.

Oprzyrządowanie kodu

Jednym z zastosowań metaprogramowania jest instrumentacja programów w celu przeprowadzenia dynamicznej analizy programu .

Zmiany behawioralne

Metaprogramowanie może być używane do wplatania zmian behawioralnych w programie, tak jak w przypadku programowania aspektowego . Na przykład metaprogramowanie może być używane do wstrzykiwania flag funkcji lub do eksploracji możliwych łat do naprawiania błędów.

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 lub nieprawidłowe użycie metaprogramowania może skutkować nieuzasadnionymi i nieoczekiwanymi błędami, które mogą być niezwykle trudne do debugowania dla przeciętnego programisty. Może wprowadzać zagrożenia do systemu i czynić go bardziej podatnym, jeśli nie jest używany z ostrożnością. 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ć nieznanymi wyjątkami lub różnymi wynikami. Z tego powodu niektórzy uważają, że tylko wysoko wykwalifikowani programiści powinni pracować nad opracowywaniem 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

Asemblery makr

IBM / 360 i pochodne miał potężne makro asemblera obiektów, które były często wykorzystywane do generowania kompletny montaż językowych programów lub fragmentów programów (dla różnych systemów operacyjnych, na przykład). Makra dostarczane z systemem 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

Metaprogramowanie etapowe

Typy zależne

Użycie typów zależnych pozwala udowodnić, że wygenerowany kod nigdy nie jest nieprawidłowy. Jednak takie podejście jest nowatorskie i rzadko można je znaleźć poza naukowymi językami programowania.

Realizacje

Lista godnych uwagi systemów metaprogramowania znajduje się na Liście Systemów Transformacji Programów .

Zobacz też

Bibliografia

Zewnętrzne linki