Czym właściwie jest metaprogramowanie?

128

Czytałem artykuł na TheServerSide o programowaniu ployglot na platformie Java . Niektóre komentarze w artykule odnoszą się do metaprogramowania jako możliwości generowania kodu (być może w locie).

Czy metaprogramowanie to możliwość generowania kodu w locie, czy też możliwość wstrzykiwania metod i atrybutów do istniejących obiektów w czasie wykonywania (na przykład na to, co pozwalają niektóre języki dynamiczne, takie jak Python, Ruby i Groovy).

Parag
źródło
7
Może Cię zainteresuje ta odpowiedź stackoverflow.com/questions/2565572/…
ewernli
@ewernli: Ta odpowiedź jest właściwie lepsza niż którakolwiek z odpowiedzi tutaj!
JD

Odpowiedzi:

100

Metaprogramowanie odnosi się do różnych sposobów, w jakie program posiada wiedzę o sobie lub może sobą manipulować.

W językach takich jak C # refleksja jest formą metaprogramowania, ponieważ program może badać informacje o sobie. Na przykład zwrócenie listy wszystkich właściwości obiektu.

W językach takich jak ActionScript można oceniać funkcje w czasie wykonywania, aby tworzyć nowe programy, takie jak eval („x” + i). Funkcja DoSomething () wpłynie na obiekt o nazwie x1, gdy i wynosi 1, a x2, gdy i wynosi 2.

Wreszcie inną popularną formą metaprogramowania jest to, że program może zmienić się w nietrywialne mody. LISP jest z tego dobrze znany i jest czymś, co Paul Graham bronił około dekady temu. Będę musiał przejrzeć niektóre z jego konkretnych esejów. Ale chodzi o to, że program zmieniłby inną część programu na podstawie jej stanu. Zapewnia to poziom elastyczności przy podejmowaniu decyzji w czasie wykonywania, który jest bardzo trudny w większości popularnych języków.

Warto również zauważyć, że w dawnych dobrych czasach programowania w prostym asemblerze programy, które zmieniały się w czasie wykonywania, były konieczne i bardzo powszechne.

Z eseju Paula Grahama „What Made Lisp Different” :

Wiele języków ma coś, co nazywa się makro. Ale makra Lisp są wyjątkowe. Wierz lub nie, ale to, co robią, jest związane z nawiasami. Projektanci Lispa nie umieścili tych wszystkich nawiasów w języku tylko po to, by być innym. Dla programisty Bluba kod Lispa wygląda dziwnie. Ale te nawiasy są tam z jakiegoś powodu. Są zewnętrznym dowodem fundamentalnej różnicy między Lispem a innymi językami.

Kod Lisp składa się z obiektów danych Lisp. I nie w tym trywialnym sensie, że pliki źródłowe zawierają znaki, a łańcuchy są jednym z typów danych obsługiwanych przez język. Kod Lispa, po odczytaniu przez parser, składa się ze struktur danych, przez które możesz przechodzić.

Jeśli rozumiesz, jak działają kompilatory, tak naprawdę dzieje się nie tyle, że Lisp ma dziwną składnię, ale że Lisp nie ma składni. Piszesz programy w drzewach analizy, które są generowane w kompilatorze, gdy analizowane są inne języki. Ale te drzewa parsowania są w pełni dostępne dla twoich programów. Możesz pisać programy, które nimi manipulują. W Lispie te programy nazywane są makrami. Są to programy, które piszą programy.

Programy, które piszą programy? Czy kiedykolwiek chciałbyś to zrobić? Niezbyt często, jeśli myślisz w Cobolu. Cały czas, jeśli myślisz w Lisp. Byłoby dobrze, gdybym mógł podać przykład potężnego makra i powiedzieć, że tam! co ty na to? Ale gdybym to zrobił, wyglądałoby to jak bełkot dla kogoś, kto nie znał Lispa; nie ma tu miejsca na wyjaśnienie wszystkiego, co musisz wiedzieć, aby zrozumieć, co to oznacza. W Ansi Common Lisp starałem się przesuwać rzeczy tak szybko, jak tylko mogłem, a mimo to nie dotarłem do makr do strony 160.

Myślę jednak, że mogę przedstawić argument, który może być przekonujący. Kod źródłowy edytora Viaweb zawierał prawdopodobnie około 20-25% makr. Makra są trudniejsze do napisania niż zwykłe funkcje Lispa i uważa się, że złym stylem jest używanie ich, gdy nie są potrzebne. Więc każde makro w tym kodzie istnieje, ponieważ musi być. Oznacza to, że co najmniej 20-25% kodu w tym programie robi rzeczy, których nie można łatwo zrobić w żadnym innym języku. Jakkolwiek sceptyczny programista Bluba może odnosić się do moich roszczeń co do tajemniczych mocy Lispa, to powinno go zaciekawić. Nie pisaliśmy tego kodu dla własnej rozrywki. Byliśmy małym startupem, programowaliśmy tak ciężko, jak tylko mogliśmy, aby stawiać bariery techniczne między nami a naszymi konkurentami.

Podejrzana osoba mogłaby zacząć się zastanawiać, czy jest tu jakaś korelacja. Duża część naszego kodu wykonywała rzeczy, które są bardzo trudne do wykonania w innych językach. Powstałe oprogramowanie robiło rzeczy, których nie potrafiło oprogramowanie naszych konkurentów. Może był jakiś związek. Zachęcam do śledzenia tego wątku. W tym starcu kulejącym o kulach może być coś więcej niż na pierwszy rzut oka.

DavGarcia
źródło
6
Nie zapomnij o metaprogramowaniu szablonów w C ++. Możliwość wykonywania wyrażeń i podejmowania decyzji w czasie kompilacji oraz statycznego kompilowania wyników do końcowego pliku wykonywalnego.
Remy Lebeau
1
Byłem zszokowany in order to put technical barriers between us and our competitorsi to jest poprawne.
Evan Hu
4
Programy, które same siebie manipulują, stanowią podzbiór wszystkich metaprogramów. Ogólnie metaprogramowanie oznacza po prostu programy, które manipulują programami.
JD
55

Świetne pytanie. Bardzo mi przykro, że żadna z odpowiedzi nie odpowiada obecnie poprawnie na Twoje pytanie. Może mogę pomóc ...

Definicja metaprogramowania jest naprawdę prosta: oznacza programy, które manipulują programami.

Twoja zaakceptowana odpowiedź mówi o programach, które manipulują sobą. To są rzeczywiście metaprogramy, ale stanowią one podzbiór wszystkich metaprogramów.

Wszystko:

  • Parsery
  • Języki specyficzne dla domeny (DSL)
  • Wbudowane języki specyficzne dla domeny (EDSL)
  • Kompilatory
  • Tłumacze
  • Korektorzy terminów
  • Dowody twierdzeń

są metaprogramami. Więc kompilator GCC jest metaprogramem, interpreter CPythona jest metaprogramem, system algebry komputerowej Mathematica jest metaprogramem, dowód twierdzenia Coqa jest metaprogramem i tak dalej.

Inne odpowiedzi twierdzą, że metaprogramy to programy, które generują inne programy. To są rzeczywiście metaprogramy, ale znowu są one podzbiorem wszystkich metaprogramów. Najszybsza transformaty Fouriera na Zachodzie (FFTW) biblioteka jest przykładem takiego metaprogram. Kod źródłowy jest napisany głównie w OCaml i generuje bity kodu C (zwane kodami), które są łączone w celu utworzenia wysokowydajnych procedur szybkiej transformacji Fouriera zoptymalizowanych dla określonych maszyn. Ta biblioteka jest faktycznie używana do dostarczania procedur FFT w Matlabie. Ludzie piszą programy do generowania metod numerycznych od dziesięcioleci, od początku istnienia FORTRANU .

Pierwszym językiem programowania, który zintegrował obsługę metaprogramowania, był język LISt Processor (LISP) pod koniec lat pięćdziesiątych. LISP 1.5 zawierał szereg funkcji ułatwiających metaprogramowanie. Po pierwsze, podstawowym typem danych LISP są listy zagnieżdżone, tj. Drzewa (a (b c) d), co oznacza, że ​​każdy kod LISP może być wyrażony natywnie jako struktura danych. Nazywa się to homoikonicznością. Po drugie, kod LISP można łatwo przekonwertować na dane za pomocą funkcji QUOTE. Na przykład (+ 1 2 3)dodaje 1 + 2 + 3 i (QUOTE (+ 1 2 3))tworzy wyrażenie, które dodaje 1 + 2 + 3 podczas oceny. Po trzecie, LISP dostarczył meta-cykliczny moduł oceniający, który umożliwia użycie interpretera hosta lub kompilatora do oceny kodu LISP w czasie wykonywania, w tym kodu LISP generowanego w czasie wykonywania. Potomkowie LISP to Scheme i Clojure. We wszystkich tych językach metaprogramowanie jest najczęściej postrzegane w postaci programów, które modyfikują się same, zwykle przy użyciu makr.

W latach 70. Robin Milner opracował MetaLanguage (ML), który wyewoluował w rodzinę języków programowania ML, obejmującą Standard ML i OCaml oraz silnie wpłynął na Haskell i F # . Te języki ułatwiają wyrażanie innych języków. W tych językach metaprogramy są najczęściej widziane w postaci lekserów, parserów, tłumaczy i kompilatorów.

W 1994 roku Erwin Unruh odkrył, że system szablonów C ++ jest kompletny w Turingu i może być używany do wykonywania dowolnych programów w czasie kompilacji . Metaprogramowanie szablonów w C ++ sprowadziło metaprogramowanie do niemytych mas, które (ab) używały go do wielu różnych rzeczy, w tym generowania metod numerycznych w bibliotece Blitz ++ .

JD
źródło
33

Cóż, metaprogramowanie to po prostu programowanie, ale to po prostu „pisanie kodu, który pisze kod” .

Zdolność, o której wspominasz, kiedy program może obserwować i modyfikować swoją własną strukturę i zachowanie, nazywa się odbiciem i jest rodzajem metaprogramowania.

Języki z typami dynamicznymi mają potężne funkcje odbicia w czasie wykonywania, możliwe dzięki interpretowanej naturze tych języków ...

Języki z typowaniem statycznym mają również potężne techniki metaprogramowania, na przykład metaprogramowanie szablonów C ++ ...

CMS
źródło
14

To tylko moja osobista opinia, która jest prawdopodobnie najbardziej liberalną definicją metaprogramowania.

Myślę, że obejmuje:

  1. Kompiluj generowanie kodu lub generowanie kodu w czasie wykonywania (lub oba)
  2. Myślenie zorientowane na aspekt lub programowanie zorientowane na aspekt
  3. Myślenie SUCHE

Myślę, że możesz się tam dostać, używając dowolnego z nich i kombinacji:

  1. Odbicie
  2. DSL (języki specyficzne dla domeny)
  3. Atrybuty (.NET) lub adnotacje (Java)
  4. Generics (.NET / Java)
  5. Szablony (C ++)
  6. brak metody (Ruby)
  7. zamknięcia / funkcje pierwszej klasy / delegaci
  8. AOP - programowanie zorientowane na aspekty
BuddyJoe
źródło
bardzo zwięzła i przemyślana odpowiedź. dał mi dobre menu rzeczy do zbadania. Dziękuję Ci!
swyx
6

Metaprogramowanie to pisanie programu, który wyprowadza inny program. Jest to coś, w czym języki takie jak Lisp są naprawdę dobre. O wiele łatwiej jest to zrobić w języku, który obsługuje prawdziwe makra (nie makra C ++, ale raczej takie, które mogą manipulować kodem, który generują), takie jak Ruby, Lisp, Scheme, itp. Niż w języku takim jak Java.

Jedną z implementacji jest stworzenie „języka specyficznego dla domeny”, który jest sposobem na ulepszenie języka programowania w celu wykonania określonego zadania. Jeśli zostanie wykonany poprawnie, może być niesamowicie potężny. Ruby on Rails jest dobrym przykładem tego rodzaju programowania.

Jeśli jesteś zainteresowany poznaniem tej metody, zapoznaj się z Structure and Interpretation of Computer Programs, która jest jedną z nowatorskich książek na ten temat.

Steve Rowe
źródło
5

Metaprogramowanie to pisanie programów komputerowych, które zapisują lub przetwarzają inne programy (lub same) jako swoje dane, lub wykonują część pracy w czasie wykonywania, która w innym przypadku byłaby wykonywana w czasie kompilacji. W wielu przypadkach pozwala to programistom na wykonanie większej ilości pracy w tym samym czasie, jaki zajęłoby ręczne napisanie całego kodu, lub daje programom większą elastyczność w efektywnym radzeniu sobie z nowymi sytuacjami bez ponownej kompilacji. ( Źródło .)

Zasadniczo jest to pisanie kodu, który generuje więcej kodu, który jest uruchamiany, aby osiągnąć jakiś cel. Zwykle odbywa się to w tym samym języku (używając javascript do utworzenia łańcucha javascript, a następnie evalgo) lub w innym języku (używając .NET do utworzenia pliku wsadowego systemu Windows).

EndangeredMassa
źródło
4

wikipedia ma fajny artykuł na ten temat. Nie trzeba wprowadzać modyfikacji w czasie wykonywania, aby coś kwalifikować się jako metaprogramowanie. Na przykład wiele osób używa szablonów C ++ do metaprogramowania w czasie kompilacji.

Panie Fooz
źródło