A C++ template metaprogramozás és a funkcionális programozás kapcsolata Doktori értekezés tézisei 2013 Sinkovics Ábel abel@elte.hu Témavezető: Porkoláb Zoltán, egyetemi docens Eötvös Loránd Tudományegyetem, Informatika kar, 1117 Budapest, Pázmány Péter sétány 1/C ELTE IK Doktori Iskola Doktori program: Az informatika alapjai és módszertana Az iskola vezetője: Dr. Benczúr András akadémikus A doktori program vezetője: Dr. Demetrovics János akadémikus
A projekt az Európai Unió támogatásával, az Európai Szociális Alap társfinanszírozásával valósul meg (a támogatás száma TAMOP 4.2.1./B-09/1/KMR-2010-0003). 2
1. Bevezetés A dolgozat C++ template metaprogramozást segítő módszereket mutat be, melyek a C++ könyvtárak és alkalmazások fejlesztőit támogatják. A dolgozat azon fejlesztők számára készült, akik már ismerik a C++ programozási nyelvet. 1994-ben Erwin Unruh bemutatta [32], hogy lehetséges egy C++ fordító segítségével, template példányosítások mellékhatásaként algoritmusokat végrehajtani. Az ezen a módszeren alapuló programokat C++ template metaprogramok nak hívják. Ezek egy Turing-teljes résznyelvét alkotják a C++-nak [35]. A metaprogramokat a fejlesztők többsége nem közvetlenül használja, hanem metaprogramokon alapuló könyvtárakon keresztül. Mivel a template metaprogramok fordítási időben kerülnek végrehajtásra, segítségükkel a C++ nyelvnek számos kiterjesztését meg lehet valósítani a fordító módosítása nélkül. Speciális alkalmazási területet (adatbázis elérés, reguláris kifejezések, stb.) támogató C++ könyvtárak számára hasznos ha az alkalmazási területtel kapcsolatos hibákat (adatbázis mezőinek típusaival kapcsolatos hibák, hibás reguláris kifejezések, stb.) már fordítási időben jelezni lehet. Template metaprogramok segítségével megvalósíthatók ilyen ellenőrzések [7]. A domén specifikus nyelvek (DSL) [6] egyre népszerűbbek. Ezek egyszerű nyelvek, melyeket egy adott terület számára fejlesztettek ki. Azon a területen hatékonyabbak, mint más nyelvek, viszont más területeken használhatatlanok. Vannak széles körben ismert és használt domén specifikus nyelvek, mint például az SQL vagy a reguláris kifejezések. Ezeket a nyelveket egy (vagy több) általános célú programozási nyelvvel együtt szokták használni. A DSL által lefedett területre specifikus részeit a programnak a DSL-ben, a többi részt pedig az általános célú nyelven szokták megírni. Amikor a DSL-ben írt kódrészleteket beágyazzák az általános célú nyelven írt kódba, beágyazott DSL-ekről (EDSL) beszélünk. Template metaprogramok segítségével DSL-ek hatékonyan beágyazhatók a C++ nyelvbe [27]. A fejlesztők gyakran kénytelenek ismétlődő, csupán kevés részletben különböző kódot írni. Az esetek többségében ezeket a kódrészleteket meglévő kód másolásával és módosításával készítik el. Template metaprogramok használatával elérhető, hogy a C++ fordító generálja ezeket a kódrészleteket [1]. 2
A C++ fordítók optimalizálják a kódot, hogy gyorsabban fusson vagy kevesebb memóriát használjon. Azonban a fordító csak olyan optimalizációkat hajthat végre, melyek a kód működését nem változtatják meg. Sok esetben ennél hatékonyabb optimalizációkat is el lehet végezni azon alkalmazási területnek és annak szabályszerűségeinek ismeretében, mely számára a program készült. Ezeket a fordító nem ismeri, azonban ezek a optimalizációk template metaprogramok segítségével megvalósíthatók [34, 36, 33]. Amikor új elemek kerülnek a C++ nyelvbe vagy amikor valaki ki szeretne próbálni egy újonnal kitalált nyelvi elemet, a fordítót módosítani kell, hogy támogassa azt. Ez azonban sokszor nehézkes vagy nem is lehetséges. Ellenben template metaprogramok segítségével számos nyelvi elemet lehet szimulálni [37]. A C++ template metaprogramok megvalósíthatók szabványos C++ kóddal, így minden fordító, mely a szabványt követi képes értelmezni és végrehajtani őket. 2. Célkitűzések A C++ nyelv fejlesztése során nem volt cél a template metaprogramozás támogatása. Ennek eredményeképpen a metaprogramok szintaxisa bonyolult lett. Metaprogramokat nehéz olvasni, írni és karbantartani. A C++ template metaprogramozás és a funkcionális paradigma kapcsolata jól ismert [13, 3, 14, 5, 16, 30, 8, 9]. Számos hasonlóság van a C++ template metaprogramozás és a funkcionális nyelvek, mint például a Haskell logikája között. Futási időben végrehajtott C++ kód készítéséhez vannak könyvtárak, melyek a funkcionális programozást támogatják [12, 4], viszont template metaprogramozásban a jelenleg használt módszerek [1, 10, 2] az imperatív nyelveket és könyvtárakat szimulálják. A dolgozat megvizsgálja, hogy a template metaprogramok olvashatóságát milyen módon lehet a funkcionális paradigma mentén javítani. A dolgozat két módszert tárgyal. Az egyik módszer a jelenleg használt eszközöket és módszereket bővíti funkcionális nyelvekben gyakori elemekkel. Többek között bevezeti az algebrai adattípusokat, let kifejezéseket, mintaillesztést, a curry-zés és a typeclass fogalmát. Bemutatja továbbá, hogy hogyan lehet implementálni a monádokat, melyek segítségével megvalósítható a list comprehension, illetve szimulálható a kivételkezelés. 3
A másik módszer egy Haskell-szerű DSL-t valósít meg a template metaprogramozás számára. Az ezen a nyelven írt metaprogramokat karakterlánc literálokban lehet C++ kódba ágyazni. A C++ kód fordításakor ezek metaprogramokká lesznek alakítva és rögtön végrehajtásra kerülnek. Ennek megvalósításához a dolgozat bemutatja, miként lehet karakterlánc literálokat template metaprogramokkal feldolgozni. Ez lehetővé teszi a DSL-ek hatékony beágyazását C++-ba, melyre a dolgozat alkalmazási példákat mutat be. 3. Eredmények Annak ellenére, hogy a template metaprogramozás és a funkcionális paradigma hasonlóságai ismertek, a gyakorlatban használt metaprogramokat nem a funkcionális paradigma mentén készítik. Ez a dolgozat két módszert mutat be, melyek template metaprogramoknak a funkcionális paradigma alapján történő fejlesztését támogatják. A bemutatott módszerek a C++11 szabványt használják, bármely szabványos fordítóval használhatók. Egyikük sem igényel további eszközöket. Az 1. ábra bemutatja a dolgozat logikai szerkezetét. A felhő jelöli a dolgozat alapgondolatát, a lekerekített sarkú téglalapok a tézisek. A fejezetek számai, melyekben egy adott téma ki van fejtve kis téglalapokban vannak az ábrán felüntetve. A vastag szürke keretes téglalapok jelölik az adott módszerek használatából származó előnyöket. Az első módszer funkcionális nyelvek alapvető elemeit valósítja meg template metaprogramozásban, majd ezekre alapozva magasabb szintű elemeket épít. A bevezetett elemek mind a széles körben használt Boost.MPL könyvtárra épülnek, ezért bármely programban könnyen bevezethetők, mely ezt a könyvtárat már használja. 1. Tézis: Megvizsgáltam a C++ template metaprogramozás és a funkcionális programozási nyelvek kapcsolatát. Az eredmények alapján kidolgoztam módszereket, melyek a funkcionális paradigmát követő fejlszetőket segítik template metaprogramok írásában. (III. fejezet) 1.1. Tézis: Megmutattam a lusta kiértékelés jelentőségét a template metaprogramozásban és kidolgoztam egy módszert, melynek segítségével lusta kiértékelést nem támogató metafüggvényeket is lehet olyan módon használni, mintha támogatnák azt. (III.1. fejezet) 1.2. Tézis: Kidolgoztam egy módszert a curry-zés hatékony megvalósítására C++ template metaprogramozásban. (III.2. fejezet) 1.3. Tézis: Kidolgoztam egy módszert a Haskell nyelvben használthoz hasonló algebrai adattípusok megvalósítására C++ template metaprogramozásban. (III.3. fejezet) 4
1. ábra. A dolgozat szerkezete 5
1.4. Tézis: Kidolgoztam egy módszert Haskell typeclass-ok megvalósítására C++ template metaprogramozásban. (III.4. fejezet) 1.5. Tézis: Kidolgoztam egy módszert, melynek segítségével template metaprogramozásbeli kifejezéseket lehet tárolni, paraméterként átadni vagy függvényhívás eredményeként visszaadni. Ez a módszer lehetővé teszi let kifejezések megvalósítását és ad egy a Boost.MPL által biztosított és széles körben használtnál hatékonyabb módszert lambda kifejezések megvalósítására. (III.5. fejezet) 1.6. Tézis: Kidolgoztam egy új módszert a mintaillesztés megvalósítására C++ template metaprogramozásban, mely lehetővé teszi case kifejezések használatát. (III.6. fejezet) A dolgozat bemutatja, hogy az 1. Tézisben bemutatott módszer alapján hogyan valósítható meg egy funkcionális nyelvekben gyakori absztrakció, a monádok és egy Haskell által biztosított szintaktikai egyszerűsítés, a do notation. Ennek felhasználásával számos hasznos eszköz készíthető. Template metaprogramozásban biztosítani lehet a list comprehension nevű módszert, mely egyszerűbbé és olvashatóbbá teszi a listákon végzett műveleteket. A monádok egyszerűsítik a template metaprogramok végrehajtása során fellépő hibák kezelését. A dolgozat bemutatja, hogyan lehet template metaprogramozásban szimulálni a kivételkezelést. 2. Tézis: Kidolgoztam egy módszert monádok és egy a Haskell által biztosítotthoz hasonló do notation megvalósítására template metaprogramozásban. Megvizsgáltam számos, Haskellben elérhető monád variációról, hogy ezzel a módszerrel hogyan valósítható meg C++ template metaprogramozásban. Kidolgoztam egy módszert a kivételkezelés szimulálására C++ template metaprogramozásban. (IV. fejezet) 2.1. Tézis: Kidolgoztam egy módszert a monádok megvalósítására C++ template metaprogramozásban. (IV.1. fejezet) 2.2. Tézis: Megvizsgáltam számos Haskellben elérhető monádról, hogy a 2.1. Tézisben bemutatott módszerrel miként lehet őket implementálni. (IV.2. fejezet) 2.3. Tézis: Kidolgoztam egy módszert a do notation megvalósítására template metaprogramozásban, mely a Haskell által biztosítotthoz hasonló. (IV.3. fejezet) 2.4. Tézis: Kidolgoztam egy monádokon alapuló módszert a kivételkezelés szimulálására C++ template metaprogramozásban. (IV.4. fejezet) 6
A dolgozat bemutat két különböző módszert a template metaprogramok olvashatóságának javítására a funkcionális paradigmával való kapcsolat felhasználásával. Az első két tézis a meglévő eszközöket és módszereket terjeszti ki funkcionális nyelvekben gyakran használt elemekkel. A harmadik tézis mutatja be a másik módszert, mely karakterlánc literálokban szereplő kódrészletek értelmezésén alapszik és ennek segítségével egy interpretert valósít meg, mely template metaprogramokat hajt végre. Egy beágyazott kódrészlet értelmezése és végrehajtása ugyanabban a fordítási lépésben történik meg, mely lehetővé teszi egy Haskell-szerű szintaxis biztosítását template metaprogramok számára. 3. Tézis: Kidolgoztam egy módszert parser-eket generáló könyvtárak megvalósítására C++ template metaprogramozásban. Megvizsgáltam, hogy ez miként használható domén specifikus nyelvek C++ nyelvbe ágyazására, illetve template metaprogramok számára egy jobban olvasható szintaxis biztosítására. Ezen módszerek egyike sem igényel külső előfordítót. (V. fejezet) 3.1. Tézis: Kidogloztam egy módszert karakterlánc literálok C++ template metaprogramokkal feldolgozható karakter konténerekké történő átalakítására. Erre alapozva kidolgoztam egy módszert parser-eket generáló könyvtárak megvalósítására C++ template metaprogramozásban. (V.1. fejezet) 3.2. Tézis: Megvizsgáltam, hogy a 3.1. Tézisben bemutatott módszerrel hogyan lehet domén specifikus nyelveket külső eszközök nélkül beágyazni a C++ nyelvbe. (V.2. fejezet) 3.3. Tézis: Megvizsgáltam, hogy a 3.1. Tézisben bemutatott módszerrel hogyan lehet egy a Haskell nyelvre hasonlító szintaxist biztosítani template metaprogramokhoz külső előfordító használata nélkül. (V.3. fejezet) 4. Összegzés A dolgozat két, a funkcionális paradigmán alapuló módszert mutat be a C++ template metaprogramok olvashatóságának és karbantarthatóságának javítására. Az egyik módszer természetes kiterjesztése a gyakorlatban használt módszereknek és eszközöknek, míg a másik egyszerű szintaxist biztosít a metaprogramok számára. A bemutatott módszerek egy nyílt forrású könyvtár gyűjteményben [21] implementálásra kerültek, mely letölthető és a módszerek nyújtotta előnyök kihasználhatók. A 2. táblázat a Cloc [15] eszköz segítségével készült és a könyvtárak, azok teszjei továbbá a kapcsolódó példák kódjaiban, illetve a dokumentációban szereplő sorok számát mutatja. Az eredmények illetve a könyvtárak be lettek mutatva a C++/Boost közösségnek. Az előadás Best Presentation díjat nyert a C++Now konferencián 2012-ben Aspenben. 7
1. táblázat. Kapcsolódó publikációk [17] [18] [19] [20] [22] [23] [24] [25] [26] [27] [28] [29] [31] 1.1 1.2 1.3 1.4 1.5 1.6 2.1 2.2 2.3 2.4 3.1 3.2 3.3 Hivatkozások 2. táblázat. Sorok száma az Mpllibs kódjában Language files blank comment code HTML 186 408 0 12383 C/C++ Header 232 2316 1159 10323 C++ 182 2734 1446 8448 CMake 32 110 132 160 CSS 1 19 7 64 YAML 1 0 0 19 [1] Abrahams, D., and Gurtovoy, A. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond (C++ in Depth Series). Addison-Wesley Professional, 2004. ISBN: 0321227255. [2] Alexandrescu, A. Modern C++ design: generic programming and design patterns applied. Addison-Wesley Longman Publishing Co., Inc., Boston, MA, USA, 2001. ISBN: 0-201-70431-5. [3] Caro, M. Haskell to c++ template metaprogramming translator, 2010. http://code.google.com/p/phaskell/w/list. [4] de Guzman, J., Marsden, D., and Heller, T. Boost.phoenix, 2010. http://www.boost.org/libs/phoenix. 8
[5] Érdi, G. Haskell to c++ template metaprogramming translator, 2010. http://gergo.erdi.hu/projects/metafun/. [6] Fowler, M. Domain-specific Languages. Addison-Wesley, 2010. ISBN: 0321712943. [7] Gil, J. Y., and Lenz, K. Simple and safe sql queries with c++ templates. Sci. Comput. Program. 75 (July 2010), 573 595. [8] Golodetz, S. Functional programming using c++ templates (part 1). Overload, 81 (October 2007). http://www.accu.org/var/uploads/journals/overload81.pdf. [9] Golodetz, S. Functional programming using c++ templates (part 2). Overload, 82 (December 2007). http://www.accu.org/var/uploads/journals/overload82.pdf. [10] Gurtovoy, A., and Abrahams, D. Boost.mpl, 2004. http://www.boost.org/libs/mpl. [11] Horváth, Z., Plasmeijer, R., and Zsók, V., Eds. Central European Functional Programming School - Third Summer School, CEFP 2009, Budapest, Hungary, May 21-23, 2009 and Komárno, Slovakia, May 25-30, 2009, Revised Selected Lectures (2010), vol. 6299 of Lecture Notes in Computer Science, Springer. [12] McNamara, B., and Smaragdakis, Y. Functional programming in c++ using the fc++ library. SIGPLAN Notices 36, 4 (2001), 25 30. [13] Milewski, B. What does haskell have to do with c++?, 2009. http://bartoszmilewski.wordpress.com/2009/10/21/what-does-haskellhave-to-do-with-c/. [14] Muñoz, J. M. L. Monads in c++ template metaprogramming, 2008. http://bannalia.blogspot.com/2008/06/monads-in-c-templatemetaprogramming.html. [15] Northrop Grumman Corporation. Cloc- count lines of code, 2013. http://cloc.sourceforge.net/. [16] Porkoláb, Z. Functional programming with c++ template metaprograms. In Horváth et al. [11], pp. 306 353. 9
[17] Porkoláb, Z., and Sinkovics, Á. Domain-specific language integration with compile-time parser generator library. In Generative Programming And Component Engineering, Proceedings of the Ninth International Conference on Generative Programming and Component Engineering, GPCE 2010, Eindhoven, The Netherlands, October 10-13, 2010 (2010), E. Visser and J. Järvi, Eds., ACM, pp. 137 146. [18] Porkoláb, Z., Sinkovics, Á., and Siroki, I. Dsl in c++ template metaprogram, tutorial, 2013. http://dsl2013.math.ubbcluj.ro/files/lecture/porkolabetal TemplateMetaprogramming.pdf. [19] Sinkovics, Á. Functionalextensionstotheboostmetaprogramlibrary. In WGT 10 (2010), Z. Porkoláb and N. Pataki, Eds., vol. II of WGT Proceedings, Zolix, pp. 56 66. [20] Sinkovics, Á. Functionalextensionstotheboostmetaprogramlibrary. Electr. Notes Theor. Comput. Sci. 264, 5 (2010), 85 101. [21] Sinkovics, Á. The source code of mpllibs, 2010. http://github.com/sabel83/mpllibs. [22] Sinkovics, Á. Nested lamda expressions with let expressions in c++ template metaprorgams. In WGT 11 (2011), Z. Porkoláb and N. Pataki, Eds., vol. III of WGT Proceedings, Zolix, pp. 63 76. [23] Sinkovics, Á. Boosting mpl with haskell elements, 2013. http://www.youtube.com/watch?v=aij034vcud8. [24] Sinkovics, Á., and Abrahams, D. Using strings in c++ template metaprograms, 2012. http://cpp-next.com/archive/2012/10/using-strings-in-c-templatemetaprograms/. [25] Sinkovics, Á., and Porkoláb, Z. Expressing c++ template metaprograms as lamda expressions. In Horváth et al. [11], pp. 97 111. [26] Sinkovics, Á., and Porkoláb, Z. Implementing monads for c++ template metaprograms. Technical Report TR-01/2011, Eötvös Loránd University, Faculty of Informatics, Dept. of Programming Languages and Compilers, Sept. 2011. [27] Sinkovics, Á., and Porkoláb, Z. Domain-specific language integration with c++ template metaprogramming. Formal and Practical 10
Aspects of Domain-Specific Languages: Recent Developments (2012), 32. ISBN: 1466620927. [28] Sinkovics, Á., and Porkoláb, Z. Metaparse - compile-time parsing with c++ template metaprogramming, 2012. http://cppnow.org/files/2012/04/sinkovics.porkol%c3%a1b.pdf. [29] Sinkovics, Á., and Porkoláb, Z. Implementing monads for c++ template metaprograms. Science of Computer Programming 78, 0 (2013), 1600 1621. [30] Sipos, Á., Porkoláb, Z., and Zsók, V. Meta fun - towards a functional-style interface for c++ template metaprograms. Studia Universitatis Babes-Bolyai Informatica LIII, 2008/2 (2008), 55 66. [31] Szűgyi, Z., Sinkovics, Á., Pataki, N., and Porkoláb, Z. C++ metastring library and its applications. In GTTSE (2009), J. M. Fernandes, R. Lämmel, J. Visser, and J. Saraiva, Eds., vol. 6491 of Lecture Notes in Computer Science, Springer, pp. 461 480. [32] Unruh, E. Prime number computation, 1994. ANSI X3J16-94-0075/ISO WG21-462. [33] Veldhuizen, T. Expression templates. C++ Report 7 (1995), 26 31. [34] Veldhuizen, T. Using C++ template metaprograms. SIGS Publications, Inc., New York, NY, USA, 1996, pp. 459 473. [35] Veldhuizen, T. L. C++ templates are turing complete. Tech. rep., 2003. [36] Veldhuizen, T. L., and Gannon, D. Active libraries: Rethinking the roles of compilers and libraries. In In Proceedings of the SIAM Workshop on Object Oriented Methods for Inter-operable Scientific and Engineering Computing OO 98 (1998), SIAM Press. [37] Zólyomi, I., Porkoláb, Z., and Kozsik, T. An extension to the subtype relationship in c++ implemented with template metaprogramming. In Generative Programming and Component Engineering, F. Pfenning and Y. Smaragdakis, Eds., vol. 2830 of Lecture Notes in Computer Science. Springer Berlin Heidelberg, 2003, pp. 209 227. 11