350 likes | 480 Views
Metaprogramming from University to Industry. Zolt án Porkoláb gsd@elte.hu http://gsd.web.elte.hu Dept. of Programming Languages and Compilers, Faculty of Informatics Eötvös Loránd University, Budapest. Agenda. I always knew C++ templates were the work of the Devil,
E N D
Metaprogrammingfrom University to Industry Zoltán Porkoláb gsd@elte.hu http://gsd.web.elte.hu Dept. of Programming Languages and Compilers, Faculty of Informatics Eötvös Loránd University, Budapest
Agenda I always knew C++ templates were the work of the Devil, and now I'm sure... - Cliff Click cited by Todd Veldhuisen • Parameterized types • C++ Template Metaprograms • Power of generative metaprograms • Sample usages • Open questions
Parameterized types (Generics) Widely used in modern programming languages: • ADA generics • Eiffel generics • C++ templates • Java generics: Pizza, GJ, Java 1.5 • C# generics • Clean, Generic Haskell, other functional langs.
Why generics? Conventional techniques are working only for complete types: int max( int a, int b) { if ( a > b ) return a; else return b; } double max( double a, double b) { if ( a > b ) return a; else return b; } //… classdate { /* … */ }; date d = max ( d1, d2);
PreprocessorMacro #define MAX(a,b) a > b ? a : b • Works, because a macro is typeless. • Processed not by the compiler, therefore there are a number of "secondary effects": MAX( x, y)*2 ->x > y ? x : y*2 MAX( ++x, y) -> ++x > y ? ++x : y
Macro – the limits void swap( int& x, int& y) { int temp = x; x = y; y = temp; } • Does not work with macro:a macro is typeless. • We need a facility to use type parameters.
Templates template <typename T> void swap( T& x, T& y) { T temp = x; x = y; y = temp; } • Ada generics: "a form of context-sensitive macro" • C++ templates: "a clever kind of macro that obeys the scope, naming, and type rules of C++" • Does not require different types used as arguments to be explicitly related. In particular, the argument types used as a template need not be from a single inheritance hierarchy.
C++ Function Templates • Template is not a single function • A schema to instantiate functions on request • Parameter deduction • Template instantiation • Compilaton time template <typename T> T max( T a, T b) { if ( a > b ) return a; else return b; } int i = 3, j = 6, k; double x = 3.14, y = 4.15, z; k = max(i,j); z = max(x,y);
C++ Function Templates 2. • Strong type system rules are applied int i = 3; double y = 3.14, z; z = max(i,y); // error template <typename T, typename S> T max( T a, S b) { if ( a > b ) return a; else return b; } z == 3.0; • No deduction on return type • No runtime information could be used
Explicit specialization • Explicit specialization int i = 3; double y = 3.14, z; template <typenameR, typename T, typename S> R max( T a, S b) { if ( a > b ) return a; else return b; } z = max<double>(i,y);
User specialization const char *s1 = “Hello”, *s2 = “world”; const char *s = max(s1,s2); template <> const char *max(const char *a, const char *b) { if ( strcmp(a,b) < 0 ) return a; else return b; }
Template overloading • You can provide overloadd template definitions • The compiler selects the most specific template cout << max (4,5); cout << max<double>(3.14,’6’); cout << max (“this”, “greater”); R max(S,T) T max(T, T) char *max(char *,char*)
C++ Class Templates 1. • Similar way template classes could be defined template <class T> class matrix { public: matrix( int i, int j ); matrix& operator=( const matrix &other); T at(int i, int j); //… private: vector<T> v; }; • Created always with explicit specialisation matrix<int> m(4,5);
C++ Class Templates 2. • User specialization template <> class matrix<bool> { public: matrix( int i, int j ); matrix( const matrix &other) bool at(int i, int j); private: aBetterRepresentation v; }; • Used the same way matrix<bool> m(4,5);
C++ Templates • The C++ templates were first implemented in the early ’90s • Accepted as part of the ANSI/ISO in 1994 • Erwin Unruh: 1994 unruh.cpp 30: conversion from enum to D<2> requested unruh.cpp 30: conversion from enum to D<3> requested unruh.cpp 30: conversion from enum to D<5> requested unruh.cpp 30: conversion from enum to D<7> requested unruh.cpp 30: conversion from enum to D<11> requested unruh.cpp 30: conversion from enum to D<13> requested unruh.cpp 30: conversion from enum to D<17> requested unruh.cpp 30: conversion from enum to D<19> requested
Power of C++ templates • The Compiler “executes” template metaprograms • The result is a non-templated program executed in“run-time” • In 1966 Böhm and Jacopini proved: Turing machine implementation <==> conditional and looping constructions • The C++ templates are Turing-complete in compilation time
The Factorial example The run-time solution int factorial( int n) { if ( n == 1 ) return 1; else return n*factorial(n-1); } int main() { cout << factorial(15) << endl; return 0; }
The Factorial example The metaprogram solution template <int N> struct Factorial { enum { value = N * Factorial<N-1>::value }; }; template <> struct Factorial<1> { enum { value = 1 }; }; int main() { const int fact15 = Factorial<15>::value; std::cout << fact15 << endl; return 0; }
Conditional statement template <bool condition, class Then, class Else> struct IF { typedef Then RET; }; template <class Then, class Else> struct IF<false, Then, Else> { typedef Else RET; }; template <typename T, typename S> IF< sizeof(T)<sizeof(S), S, T>::RET max(T t, S s) { if (t > s) return t; else return s; }
(Run-time) Programs vs. Metaprograms • Function • (runtime) Data • Variable • Condition • Loop • Assignment • Class • Type and constant • Symbolic names • Type selection • Recursion • No assignment
Data in Template Metaprograms • Referential transparency: No assignment • Still possible to store, modify, and retrieve data • Typelist struct NullType {}; typedef Typelist< char, Typelist<signed char, Typelist<unsigned char, NullType> > > Charlist; char signed char unsigned char NullType
Data handling template <class TList> struct Length; template <> struct Length<NullType> { enum { value = 0 }; }; template <class T, class U> struct Length <Typelist<T,U> > { enum { value = 1 + Length<U>::value }; };
Motivation int main() { const unsigned int di = 12; const unsigned int oi = 014; const unsigned int hi = 0xc; const unsigned int bi0 = binary_value("1101"); const unsigned int bi1 = binary<1100>::value; } template<unsigned long N> struct binary { // prepend higher bits to lowest bit static const int value=binary<N/10>::value*2+N%10; }; template<> struct binary<0> // specialization { static unsigned const value = 0; };
Motivation • Constant expression – array size, case label, etc… • Better code compiled • Faster in run-time • Syntactically checked – the language semantic is extended Design time Compilation time Run-time t Decisions on Stategies, policies Template metaprograms apply, automatic config of the program No change in type system Change in run-time values
Generative Metaprograms • metaprogramming: writing programs that represent and manipulate other programs or themselves (ie:reflection). Metaprograms are programs about programs. • introspection: the ability of a program to observe its own state • intercession: the ability to modify its own state Open compilers: transformations on AST Hygenic macros (Scheme) Two level languages: AspectJ, Template Haskell
Areas of Template Metaprogramming • Expression templates • Blitz+, PETE • Static interface checking • Early catch of syntactical/semantical errors • Extending the C++ type system • Introspection • Code adaption/optimalization • Language embedding
Expression templates Array a, b, c, d, e; // Object-oriented way of a = b + c + d + e double* _t1 = new double[N]; for ( int i=0; i<N; ++i) _t1[i] = b[i] + c[i]; double* _t2 = new double[N]; for ( int i=0; i<N; ++i) _t2[i] = _t1[i] + d[i]; double* _t3 = new double[N*M]; for ( int i=0; i<N; ++i) _t3[i] = _t2[i] + e[i]; for ( int i=0; i<N; ++i) a[i] = _t3[i]; delete [] _t3; delete [] _t2; delete [] _t1; // Fortran like solution: for ( int i=0; i<N; ++i) a[i] = b[i] + c[i] + d[i] + e[i];
Language embedding • SQL • Gil, et.al.: AraRat • XML parsing • Jarvi, et.al.: type-safe XML library • Regular expressions • Boost::Xpressive • Compiler embedding • boost::spirit
Language embedding • SQL example string s = ”select form ”+tName + ” where 1=1” ; if ( cond1 ) s += ” and fName1 = ” + field1; if ( cond2 ) s += ” and fName2 < ” + field2; if ( cond3 ) s += ” and fName3 = ” + field3; • Run-time errors • Injection attacks • Conversion problems
Language embedding SQL example void f() { conststring s = ( (tName / (fName1 == field1 && fName2 < field2) ) [ fName1, fName3 ] ).asSQL(); }
Language embedding Boost::Xpressive example std::string hello( "hello world!" ); sregex rex1 = sregex::compile( "(\\w+)(\\w+)!" ); sregex rex2 = (s1= +_w) >> ' ' >> (s2= +_w) >> '!'; smatch what; if( regex_match( hello, what, rex1 ) ) { std::cout << what[0] << '\n'; // whole match std::cout << what[1] << '\n'; // first capture std::cout << what[2] << '\n'; // second capture }
Embedding alternatives If you are (accidently) not a C++ programmer • .NET platform, VB, C#: • LINQ project • Java platform: • Eric Van Wijk et.al.: Attribute Grammar-based Language Extensions for Java • Stratego • TU Delft • Charles Simonyi: Intentional programming
Intentional programming Charles Simonyi • XEROX Palo Alto Bravo • Microsoft Word, Excel • Intentional software http://www.intentsoft.com
Open questions • The real expressive power • Standard tools • but: Loki from Andrei Alexandrescu • boost::mpl • Garantees (number of instantiations, etc…) • How to design? • How to debug?
Metaprogrammingfrom University to Industry Zoltán Porkoláb gsd@elte.hu http://gsd.web.elte.hu Dept. of Programming Languages and Compilers, Faculty of Informatics Eötvös Loránd University, Budapest Thank you! Questions?