Metaprogramozás

programozási paradigma

A metaprogramozás egy programozási módszer, amiben a számítógépes programok adatokként kezelnek programokat. Ez azt jelenti, hogy a program olvas, generál, elemez, transzformál egy másik programot, vagy futás közben módosítja önmagát.[1][2] Bizonyos esetekben ez lehetővé teszi, hogy a forráskód rövidebb legyen, ami lerövidítheti a fejlesztés idejét.[3] Néha ez utóbbi fordítva van, de a program rugalmasabbá válik abban, hogy újrafordítás nélkül is kezeljen új helyzeteket.

Használható arra is, hogy egyes számításokat a futásidőből áttegye fordítási időbe, és saját magát módosító kódot hoz létre. A nyelv, amin metaprogramozást végeznek, metanyelv. A manipulált program nyelve a tárgynyelv. A reflexió a programnyelvnek az a képessége, hogy önmaga metanyelve legyen.[4] A reflexió értékes eszköz a metaprogramozás támogatására.

Megközelítések szerkesztés

A metaprogramozás lehetővé teszi generikus kód fejlesztését. Nagyon hasznos, ha a nyelv képes első osztályú adattípusként kezelni saját magát, mint a Lisp, Prolog, SNOBOL, vagy Rebol nyelvek. A generikus programozás lehetővé teszi, hogy úgy lehessen kódolni, hogy nem specifikáljuk előre, hogy az milyen típusra vonatkozik, mivel azokat paraméterként fogják helyettesíteni használatkor.

Többnyire a következő módok valamelyike áll a metaprogramozás mögött:[5]

  • Futásidőben elérhető a futtató környezet belseje a futtatott kódból egy API-n keresztül. Ilyen a .NET IL kibocsátó.
  • Programkódot tartalmazó kifejezések dinamikus végrehajtása. A kódot gyakran karakterláncokból állítják össze, de másként is létrehozható paraméterekből és környezetből, mint például JavaScript.[* 1] Így program ír programot.

Habár a legtöbb nyelv mindkét módszert lehetővé teszi, többnyire elmennek az egyik vagy a másik irányba.

A harmadik megközelítés szerint a nyelvet teljesen kívülről nézik.[5] Az általános célú programtranszformációs rendszerek a generikus metaprogramozás közvetlen implementációi, például azok a fordítók, amelyek fogadják a nyelv leírását, és bármely transzformációt elvégeznek ezeken a nyelveken. Ez lehetővé teszi, hogy bármely célnyelvre alkalmazható legyen a metaprogramozás, függetlenül attól, hogy vannak-e eszközök, amelyekkel az adott nyelven metaprogramozást lehet végezni. Ezt láthatjuk működni a Scheme programozási nyelvvel, valamint azzal, hogyan lehet túllépni a C korlátain a Scheme nyelv szerkezeteinek segítségével.[7]

Példák szerkesztés

Egy egyszerű példa ez a shell szkript, ami a generatív programozás egy példája:

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

A szkript egy 993 soros programot hoz létre, ami kiírja a számokat 1-től 992-ig. Ez ugyan nem hatékony módszer, csak bemutatja, hogyan lehet kódot generálni. Viszont a programozó egy perc alatt megírhatja, ezzel ennyi idő alatt 1000 sort generálva.

A quine egy speciális metaprogram, ami önmagát hozza létre. Egyes nyelvekben az üres program érvényes program, ezért ez a legkisebb quine az ilyen nyelveken. Ezek a programok csak tudományos jelentőséggel bírnak. 1994-ben az üres program nyerte el A legrosszabb visszaélés a szabályokkal díjat az International Obfuscated C Code Contest (IOCCC) versenyen.[8]

Nem minden metaprogram használ generikusságot. A futásidejű önmódosítás vagy az inkrementális fordítás lehetősége is felhasználható anélkül, hogy aktuálisan forráskódot generálnának. Ezeket is sok nyelv támogatja, mint C#, Forth, Frink, Groovy, JavaScript, Lisp, Lua, Perl, PHP, Python, REBOL, Ruby, Smalltalk, és Tcl.

A metaprogramozásra a Lisp nyújtja a legtöbb lehetőséget. Az unquote operátor (tipikusan a vessző) által bevezetett programszakasz definiálási időben hajtódik végre. Így a metaprogramozás nyelve ugyanaz, mint a gazdanyelv, és már létező Lisp rutinok közvetlenül használhatók metaprogramozáshoz. Más programnyelvek ezt egy értelmező beépítésével oldják meg, ami közvetlenül a program adatait elemzi. Néhány gyakran használt nyelv számára vannak ilyen implementációk, például a RemObject Pascal Scriptje az Object Pascal számára.

A metaprogramozás egy megközelítése a beágyazott nyelvek (DSL) használata. A lex és a yacc a generikus metaprogramozást szolgálja, és lexikai elemzőket és parsereket generálnak. A felhasználónak csak a megfelelő szabályos kifejezéseket és környezetfüggetlen nyelvtanokat kell megírnia, meg a nyelv hatékony parszolását végző algoritmusokat implementálnia.

Támogatás és kihívások szerkesztés

A metaprogramozás haszna az, hogy felgyorsíthatja a fejlesztést, és növeli azoknak a programozóknak a teljesítményét, akik megtanulták és begyakorolták. Néhány elemzés szerint meredek a tanulási görbe, ameddig a fejlesztő megtanulja a metaprogramozás teljes eszközkészletét, és felgyorsul.[9] Mivel nagyobb hatékonyságot és rugalmasságot ad futásidőben, hibás használata vagy a vele való visszaélés váratlan hibákat eredményezhet mindenféle figyelmeztetés nélkül, amelyeket nehezebb észrevenni és javítani. Ha nem elég körültekintően használják, akkor sérülékenyebbé teszi a rendszert. Ezek egy részét egy megfelelő fordító meg tudná előzni, ha legalább figyelmeztet a hiányzó paraméterekre, az érvénytelen vagy inkorrekt adatokra, amelyek a kívánttól eltérő eredményeket vagy ismeretlen típusú kivételeket okozhatnak.[10] Éppen ezért egyes kritikusok szerint csak képzett és tapasztalt programozóknak lenne szabad megengedni azt, hogy metaprogramozást támogató eszközöket hozzanak létre egy nyelvhez vagy környezethez, és a többi programozónak először egy konvenció részeként kell megtanulnia, hogyan bánjon velük.

Felhasználása különböző nyelvekben szerkesztés

Makrórendszerek szerkesztés

Makró assemblerek szerkesztés

Az IBM/360 és továbbfejlesztései fejlett makró assembler lehetőségekkel bírtak, amelyeket gyakran használtak arra, hogy egész Assembly programokat generáljanak [forrás?] vagy programszakaszokat hozzanak létre például különböző operációs rendszerek számára. A CICS tranzakciófeldolgozó rendszer assembler makrói COBOL utasításokat generáltak előfeldolgozó lépésként.

Más assemblerek, például az MASM, is támogatnak makrókat.

Metaosztályok szerkesztés

Metaosztályokat tartalmaznak a következők:

Template metaprogramozás szerkesztés

Staged metaprogramozás szerkesztés

Függő típusokkal szerkesztés

  • A függő típusok használata kizárja, hogy érvénytelen kód jöjjön létre.[11] Azonban ez a megközelítés bleeding-edge, és ritkán lehet vele találkozni a kutatási célokra készült nyelveken kívül.

Implementációk szerkesztés

Megjegyzések szerkesztés

  1. Például az instance_eval paramétere Rubyban lehet karakterlánc és névtelen függvény is.[6]

Hivatkozások szerkesztés

  1. Harald Sondergaard: Course on Program Analysis and Transformation. (Hozzáférés: 2014. szeptember 18.)
  2. Generative Programming (2000. április 25.). ISBN 0-201-30977-7 
  3. The Art of Metaprogrmming in Java. New Circle . [2017. február 14-i dátummal az eredetiből archiválva]. (Hozzáférés: 2014. január 28.)
  4. Programming Concepts: Type Introspection and Reflection. The Societa . (Hozzáférés: 2014. szeptember 14.)
  5. a b What Is Metaprogramming? – Part 2/2. Perpetual Enigma . (Hozzáférés: 2014. augusztus 14.)
  6. Rdoc for Class: BasicObject (Ruby 1.9.3) - instance_eval. (Hozzáférés: 2011. december 30.)
  7. Art of Metaprogramming
  8. IOCCC 1994 Worst Abuse of the Rules. [2017. május 3-i dátummal az eredetiből archiválva]. (Hozzáférés: 2017. május 2.)
  9. The challenge of metaprogramming. IanBicking.org . (Hozzáférés: 2016. szeptember 21.)
  10. Beware of Metaprogramming. Medium.com . Medium Corportation. (Hozzáférés: 2014. augusztus 21.)
  11. Chlipala, Adam (2010. június 1.). „Ur: statically-typed metaprogramming with type-level record computation”. ACM SIGPLAN Notices 45 (6), 122–133. o. DOI:10.1145/1809028.1806612. (Hozzáférés: 2012. augusztus 29.)  

Fordítás szerkesztés

Ez a szócikk részben vagy egészben a Metaprogramming című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.