CSC/ECE 517 Fall 2009/wiki2 1 ma: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(62 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Metaprogramming is the writing of a program that writes other programs. Metaprogramming is not limited to o-o languages, but it seems that about half of the languages that support metaprogramming are object oriented. Consider how metaprogramming is done in the various languages, and give an example of writing a particular metaprogram in at least two of these languages to illustrate the differences. Since the Wikipedia article on metaprogramming is not very detailed, if you do a good job, you could submit this article to Wikipedia.
= Metaprogramming =
== What is Metaprogramming? ==
'''Meta-''' (from Greek: μετά = "after", "beyond", "with", "adjacent", "self"), is a prefix used in English to indicate a concept which is an abstraction from another concept, used to complete or add to the latter.


= What is Metaprogramming? =
''Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new situations without recompilation.'' Source: [http://en.wikipedia.org/wiki/Metaprogramming]
''Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new situations without recompilation."


= Examples of Metaprogramming =
Metaprogramming is divided into runtime metaprogramming, also known as reflection, and compile time metaprogramming. Reflection is more interesting since it allows interaction and modification of objects, components and structures that do not exist at compile time.




= Metaprogramming style in various languages =
== Examples of Metaprograms ==


== A metaprogram in Ruby ==
*the compiler or interpreter of your favourite language
*Lex and Yacc
*CORBA's IDL compiler
*a Quine (a program that, when executed, prints a copy of its own source code - see QuineProgram for examples)
*Programs to generate EJB code and XML from database metadata
*Macros are nothing but special cases of metaprograms, as they are replaced by the actual code during macro expansion.


== A metaprogram in JAVA ==
Source: [http://c2.com/cgi/wiki?MetaProgramming]




== Illustrating the differences ==
== Metaprogramming style in various languages ==
 
Metaprogramming seems to have origniated in Lisp. John Foderaro mentions Lisp as a programmable programming language. Lisp facilitates reflection through the use of an interpreter implemented in the same language. Unlike Smalltalk and Lisp, Java and C++ do not feature extensive built-in reflection facilities.
 
 
=== Metaprogramming in Ruby ===
Ruby is a dynamically-typed, interpreted, object oriented language. One of the unique aspects of Ruby is its extensive reflexive metaprogramming facilities.
 
==== What makes Ruby good for metaprogramming ====
*Ruby is Dynamic and reflective
*Everything is open to change
*Blocks allow writing new control structures
*Most declarations are executable statements
*An easy syntax
 
==== Classification of metaprogramming features in Ruby ====
* The dynamic nature of Ruby supports creating classes and methods at runtime
* Methods can be defined directly on Singleton classes: class_eval can be used to define methods on singleton classes. This will then modify the behaviour of the sub classes(if any) and not the base class.
* Blocks and proc objects: Materializing a Proc and saving this in variables and sending it around is a good way to use metaprogramming to do interesting things. Lambda function is used to define proc objects
* The different evals: There are 4 different evals in Ruby
** eval: This call can take a string or binding to evaluate but not a block
** class_eval: It is just a alias for module_eval
** instance_eval: It will evaluate the string or the block in the context of the receiver. Thus it sets self to be the receiver.
** module_eval: It will evaluate the string or the block in the context of the module it is called on. Thus it is used to define new methods on singleton classes. This is the most commonly used eval call.
 
The difference between the above 4 evals can be understood with examples [http://www.elctech.com/snippets/the-difference-between-eval-class_eval-module_eval-and-instance_eval here]. Another useful external link on evals can be found [http://4loc.wordpress.com/2009/05/29/eval-module_eval-and-instance_eval/ here]
 
==== Examples ====
We begin by showing how methods can be defined dynamically in Ruby. Consider we need a method that duplicates strings eg. "foo".duplicate -> "foofoo". And a deduplicate method for removing duplication eg. "foofoo".deduplicate -> "foo". We can define such methods dynamically in Ruby. This ''dynamic'' feature in Ruby forms the simplest kind of metapgrogramming.
 
class String
  def duplicate
  self * 2
  end
  def deduplicate
  self[0, self.length/2]
  end
end
 
 
For instance attr_reader, attr_writer, attr_accessor are inbuilt keywords that declare the object properties. These are actually not just syntax, but methods defined in Module. ''These methods are written in C''. In other words, the ''object language'' here is Ruby but the ''metalanguage'' is C - Refer [http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2009/wiki2_1_ma#Appendix Appendix]. Representing the functionality for the attr_reader method as a metaprogram in Ruby.
 
class Module
  def attr_reader (*syms)
    sys.each do |sym|
      class_eval %{def #{sym} @#{sym} end}
    end
  end
end
 
 
Consider how define_method can be used dynamically in Ruby
Eagle=Class.new
e=Eagle.new
class Eagle
  define_method:fly do
  puts "I am flying"
  end
end
e.fly
Output: ''I am flying''
 
Rails becomes an all-powerful MVC framework, thanks to the metaprogramming features in Ruby.
 
''Other elaborate examples can be found in the [http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2009/wiki2_1_ma#References References] section of this wiki page. A detailed discussion on Metaprogramming in Ruby was done in the CSC517 course lecture, the notes for which can be found [http://courses.ncsu.edu/csc517/common/lectures/notes/lec12-f09.pdf here]''
 
 
=== Metaprogramming in C++ ===
 
C++ provides for a type of metaprogramming called as [http://en.wikipedia.org/wiki/Template_metaprogramming template metaprograming]. Template Metaprogramming (TMP) is a programming technique that uses the priniciple of [http://en.wikipedia.org/wiki/Name_binding early binding].  This means that pieces of codes called templates are replaced by actual code including compile-time constants, data structures, and complete functions. Then the compiler puts together all the code and compiles it. Hence the compiler in a sense acts as a "virtual computer" [http://www.codeproject.com/KB/cpp/crc_meta.aspx] as it replaces parts of the program with instructions, which would otherwise have been done at run time.
 
In TMP similar groups of lines of codes are replaced by a common template. Initially the template has to be defined with a base set of lines of code which are common in all. Then at the time of usage, templates have to be instantiated. Thus the templte definition specifies the general form of the code whereas the instantiation gives the specific lines of code formed from the template definition.
 
====Examples ====
'''Calculating a value at compile time''' <br>
The code to find summation of a number without using templates can be given as:  <br>
int summation(int n)
{
    if (n == 0 )
        return 0;
    return n + summation(n - 1);
}
void findsummation()
{
    int a = summation(5);  //a= (5+ 4 + 3 + 2 + 1 + 0) == 15
    int b = summation(0);  //b=0
}
 
Now using templates the same program can be written as:
 
template <int N>
//TEMPLATE DEFINITION
struct Summation
{
    enum { value = N + Summation<N - 1>::value }; 
};
template <>
struct Summation<0>
{
    enum { value = 0 };
};
void findsummation()
{
    int a = Summation<5>::value; // == 15    // INSTANTIATION
    int b = Summation<0>::value; // == 1    // INSTANTIATION
}
 
Thus with templates, the values of a and b were calculated at compile time rather than at run time. This was possible because 5 and 0 were literals, if they had been variables then their values wouldn’t have been known at compile time and hence a and b could not have been calculated at compile time.
 
'''Loop unrolling''' <br>
Further templates can be used to unroll loops, that is a loop is replaced by repeating the code within the loop a certain number of times. [http://www.codeproject.com/KB/cpp/crc_meta.aspx more on this example]
 
template< int i >
class LOOP{
  public:
    static inline void EXEC(){
      cout << "A-" << i << " ";
            LOOP< i-1 >::EXEC();
        cout << "B-" << i << " ";
    }
};
 
class LOOP< 0 >{
  public:
    static inline void EXEC(){
      cout << "A-" << i;
      cout << "\n";
      cout << "B-" << i;
    }
};
The output of LOOP< 8 >::EXEC() is shown below: <br>
A-8 A-7 A-6 A-5 A-4 A-3 A-2 A-1 A-0 <br>
B-0 B-1 B-2 B-3 B-4 B-5 B-6 B-7 B-8 <br>
At compile time the loop unrolls itself and produces the following lines of code:
 
cout << "A-" << 8 << " ";
cout << "A-" << 7 << " ";
...
cout << "A-" << 0;
cout << "\n";
cout << "B-" << 0;
...
cout << "B-" << 7 << " ";
cout << "B-" << 8 << " ";
 
More Examples can be found at [http://en.wikibooks.org/wiki/C++_Programming/Template/Template_Meta-Programming C++ Template Programming], [http://en.wikipedia.org/wiki/Template_metaprogramming Template Metaprogramming] and [http://www.codeproject.com/KB/cpp/crc_meta.aspx TMP in c++]
 
 
=== Illustrating the differences ===
Unlike Ruby, C++ does not support a built-in metaprogramming system aside from template metaprogramming. Template programming is also known as "programming at compile time". Templates allow the compiler to determine certain variable and object types at compile time. The disadvantages of templates are : i) it is not specialized enough (C++ templates are Turing-complete [http://homepage.mac.com/sigfpe/Computing/peano.html]. Often they can be used for collection classes but they can also be employed in metaprogramming. This can make it hard to figure out how templates can be used to solve a specific problem), ii) poor error messages (when errors occur at compile time due to incorrectness of templates, the error messages can be cryptic)
 
 
== Conclusion ==
Metaprogramming is thus an essential and useful programming feature that allows elimination of duplicated code and enables clean execution with lesser lines of code. The style of metaprogramming differs when it comes to different languages. Ruby and Lisp have more specialized metaprogramming constructs as compared to Java or C++. Metaprogramming is apparently is a higher-level concept and probably used often by expert programmers, nevertheless through metaprogramming the overall code or program becomes very easy to interpret. Its a trade-off that should be balanced by software programmers.
 
 
== Appendix ==
* Metalanguage: The language in which the metaprogram is written
* Object language: The language of the programs that are manipulated
* Reflection or Reflexivity: The ability of a programming language to be its own metalanguage
* Template: A feature of the C++ programming language that allow functions and classes to operate with generic types. This allows a function or class to work on many different data types without being rewritten for each one.
* Early Binding: In programming languages, name binding is the association of values with identifiers. The binding of names before the program is run is called early (also "static")
 
 
== References/External Links ==
# [http://en.wikipedia.org/wiki/Metaprogramming Wikipedia article on metaprogramming]
# [http://c2.com/cgi/wiki?MetaProgramming Metaprogramming]
# [http://www.codeproject.com/KB/cpp/crc_meta.aspx TMP in C++]
# [http://homepage.mac.com/sigfpe/Computing/peano.html Turing completeness in C++]
# [http://www.vanderburg.org/Speaking/Stuff/oscon05.pdf presentation about Meta programming in Ruby made at the 2005 O’Reilly Open Source Convention by Glenn Vanderburg]
# [http://theplana.wordpress.com/2007/03/12/how-to-define-a-attribute-using-metaprogramming/ Defining attributes with Metaprogramming]
# More examples on Ruby metaprogramming
## [http://ozone.wordpress.com/2006/03/02/binary-search-tree-sauce-ruby-part-1/ Link 1]
## [http://www.ruby-doc.org/core/classes/Object.src/M000366.html Link 2]
## [http://expressica.com/category/metaprogramming/ Link 3]
# [http://ozone.wordpress.com/2006/02/22/rubybeans-a-short-example-of-ruby-metaprogramming/#comment-1286 Rubybeans and Metaprogramming]
# [http://reference.jumpingmonkey.org/programming_languages/ruby/ruby-metaprogramming.html Metaprogramming in Ruby]
# [http://en.wikibooks.org/wiki/C++_Programming/Template/Template_Meta-Programming C++ Template Programming]
# [http://en.wikipedia.org/wiki/Template_metaprogramming Template Metaprogramming]

Latest revision as of 22:47, 8 October 2009

Metaprogramming

What is Metaprogramming?

Meta- (from Greek: μετά = "after", "beyond", "with", "adjacent", "self"), is a prefix used in English to indicate a concept which is an abstraction from another concept, used to complete or add to the latter.

Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data, or that do part of the work at compile time that would otherwise be done at runtime. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually, or it gives programs greater flexibility to efficiently handle new situations without recompilation. Source: [1]

Metaprogramming is divided into runtime metaprogramming, also known as reflection, and compile time metaprogramming. Reflection is more interesting since it allows interaction and modification of objects, components and structures that do not exist at compile time.


Examples of Metaprograms

  • the compiler or interpreter of your favourite language
  • Lex and Yacc
  • CORBA's IDL compiler
  • a Quine (a program that, when executed, prints a copy of its own source code - see QuineProgram for examples)
  • Programs to generate EJB code and XML from database metadata
  • Macros are nothing but special cases of metaprograms, as they are replaced by the actual code during macro expansion.

Source: [2]


Metaprogramming style in various languages

Metaprogramming seems to have origniated in Lisp. John Foderaro mentions Lisp as a programmable programming language. Lisp facilitates reflection through the use of an interpreter implemented in the same language. Unlike Smalltalk and Lisp, Java and C++ do not feature extensive built-in reflection facilities.


Metaprogramming in Ruby

Ruby is a dynamically-typed, interpreted, object oriented language. One of the unique aspects of Ruby is its extensive reflexive metaprogramming facilities.

What makes Ruby good for metaprogramming

  • Ruby is Dynamic and reflective
  • Everything is open to change
  • Blocks allow writing new control structures
  • Most declarations are executable statements
  • An easy syntax

Classification of metaprogramming features in Ruby

  • The dynamic nature of Ruby supports creating classes and methods at runtime
  • Methods can be defined directly on Singleton classes: class_eval can be used to define methods on singleton classes. This will then modify the behaviour of the sub classes(if any) and not the base class.
  • Blocks and proc objects: Materializing a Proc and saving this in variables and sending it around is a good way to use metaprogramming to do interesting things. Lambda function is used to define proc objects
  • The different evals: There are 4 different evals in Ruby
    • eval: This call can take a string or binding to evaluate but not a block
    • class_eval: It is just a alias for module_eval
    • instance_eval: It will evaluate the string or the block in the context of the receiver. Thus it sets self to be the receiver.
    • module_eval: It will evaluate the string or the block in the context of the module it is called on. Thus it is used to define new methods on singleton classes. This is the most commonly used eval call.

The difference between the above 4 evals can be understood with examples here. Another useful external link on evals can be found here

Examples

We begin by showing how methods can be defined dynamically in Ruby. Consider we need a method that duplicates strings eg. "foo".duplicate -> "foofoo". And a deduplicate method for removing duplication eg. "foofoo".deduplicate -> "foo". We can define such methods dynamically in Ruby. This dynamic feature in Ruby forms the simplest kind of metapgrogramming.

class String
 def duplicate
  self * 2
 end
 def deduplicate
  self[0, self.length/2]
 end
end
 

For instance attr_reader, attr_writer, attr_accessor are inbuilt keywords that declare the object properties. These are actually not just syntax, but methods defined in Module. These methods are written in C. In other words, the object language here is Ruby but the metalanguage is C - Refer Appendix. Representing the functionality for the attr_reader method as a metaprogram in Ruby.

class Module
 def attr_reader (*syms)
   sys.each do |sym|
      class_eval %{def #{sym} @#{sym} end}
   end
 end
end


Consider how define_method can be used dynamically in Ruby

Eagle=Class.new
e=Eagle.new
class Eagle
 define_method:fly do
  puts "I am flying"
 end
end
e.fly
Output: I am flying

Rails becomes an all-powerful MVC framework, thanks to the metaprogramming features in Ruby.

Other elaborate examples can be found in the References section of this wiki page. A detailed discussion on Metaprogramming in Ruby was done in the CSC517 course lecture, the notes for which can be found here


Metaprogramming in C++

C++ provides for a type of metaprogramming called as template metaprograming. Template Metaprogramming (TMP) is a programming technique that uses the priniciple of early binding. This means that pieces of codes called templates are replaced by actual code including compile-time constants, data structures, and complete functions. Then the compiler puts together all the code and compiles it. Hence the compiler in a sense acts as a "virtual computer" [3] as it replaces parts of the program with instructions, which would otherwise have been done at run time.

In TMP similar groups of lines of codes are replaced by a common template. Initially the template has to be defined with a base set of lines of code which are common in all. Then at the time of usage, templates have to be instantiated. Thus the templte definition specifies the general form of the code whereas the instantiation gives the specific lines of code formed from the template definition.

Examples

Calculating a value at compile time
The code to find summation of a number without using templates can be given as:

int summation(int n) 
{
    if (n == 0 )
       return 0;
    return n + summation(n - 1);
}
void findsummation()
{
    int a = summation(5);   //a= (5+ 4 + 3 + 2 + 1 + 0) == 15
    int b = summation(0);  //b=0
}

Now using templates the same program can be written as:

template <int N>
//TEMPLATE DEFINITION
struct Summation
{
    enum { value = N + Summation<N - 1>::value };  
};
template <>
struct Summation<0> 
{
    enum { value = 0 };
};
void findsummation()
{
    int a = Summation<5>::value; // == 15    // INSTANTIATION
    int b = Summation<0>::value; // == 1     // INSTANTIATION
}

Thus with templates, the values of a and b were calculated at compile time rather than at run time. This was possible because 5 and 0 were literals, if they had been variables then their values wouldn’t have been known at compile time and hence a and b could not have been calculated at compile time.

Loop unrolling
Further templates can be used to unroll loops, that is a loop is replaced by repeating the code within the loop a certain number of times. more on this example

template< int i >
class LOOP{
  public:
    static inline void EXEC(){
      cout << "A-" << i << " ";
            LOOP< i-1 >::EXEC();
       cout << "B-" << i << " ";
    }
};
class LOOP< 0 >{
  public:
    static inline void EXEC(){
      cout << "A-" << i;
      cout << "\n"; 
      cout << "B-" << i;
    }
};

The output of LOOP< 8 >::EXEC() is shown below:
A-8 A-7 A-6 A-5 A-4 A-3 A-2 A-1 A-0
B-0 B-1 B-2 B-3 B-4 B-5 B-6 B-7 B-8

At compile time the loop unrolls itself and produces the following lines of code:

cout << "A-" << 8 << " ";
cout << "A-" << 7 << " ";
...
cout << "A-" << 0;
cout << "\n"; 
cout << "B-" << 0;
...
cout << "B-" << 7 << " ";
cout << "B-" << 8 << " ";

More Examples can be found at C++ Template Programming, Template Metaprogramming and TMP in c++


Illustrating the differences

Unlike Ruby, C++ does not support a built-in metaprogramming system aside from template metaprogramming. Template programming is also known as "programming at compile time". Templates allow the compiler to determine certain variable and object types at compile time. The disadvantages of templates are : i) it is not specialized enough (C++ templates are Turing-complete [4]. Often they can be used for collection classes but they can also be employed in metaprogramming. This can make it hard to figure out how templates can be used to solve a specific problem), ii) poor error messages (when errors occur at compile time due to incorrectness of templates, the error messages can be cryptic)


Conclusion

Metaprogramming is thus an essential and useful programming feature that allows elimination of duplicated code and enables clean execution with lesser lines of code. The style of metaprogramming differs when it comes to different languages. Ruby and Lisp have more specialized metaprogramming constructs as compared to Java or C++. Metaprogramming is apparently is a higher-level concept and probably used often by expert programmers, nevertheless through metaprogramming the overall code or program becomes very easy to interpret. Its a trade-off that should be balanced by software programmers.


Appendix

  • Metalanguage: The language in which the metaprogram is written
  • Object language: The language of the programs that are manipulated
  • Reflection or Reflexivity: The ability of a programming language to be its own metalanguage
  • Template: A feature of the C++ programming language that allow functions and classes to operate with generic types. This allows a function or class to work on many different data types without being rewritten for each one.
  • Early Binding: In programming languages, name binding is the association of values with identifiers. The binding of names before the program is run is called early (also "static")


References/External Links

  1. Wikipedia article on metaprogramming
  2. Metaprogramming
  3. TMP in C++
  4. Turing completeness in C++
  5. presentation about Meta programming in Ruby made at the 2005 O’Reilly Open Source Convention by Glenn Vanderburg
  6. Defining attributes with Metaprogramming
  7. More examples on Ruby metaprogramming
    1. Link 1
    2. Link 2
    3. Link 3
  8. Rubybeans and Metaprogramming
  9. Metaprogramming in Ruby
  10. C++ Template Programming
  11. Template Metaprogramming