CSC/ECE 517 Spring 2013/ch1b 1k hf: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
(→‎Uses of Metaprogramming: modified list of uses so that it will match up with later examples)
No edit summary
 
(27 intermediate revisions by 2 users not shown)
Line 1: Line 1:
*Here is a [https://docs.google.com/a/ncsu.edu/document/d/1aER6f9EDFJaUMgSpK7g5nYPiMNoUjZzwQxzY0jMW8mI/edit link] to the writing assignment for this topic.
*Here is a [https://docs.google.com/a/ncsu.edu/document/d/1aER6f9EDFJaUMgSpK7g5nYPiMNoUjZzwQxzY0jMW8mI/edit link] to the writing assignment for this topic.
*Here is a [[CSC/ECE_517_Fall_2011/ch4_4g_as|link]] to previous work on this topic.
*Here is a [[CSC/ECE_517_Fall_2011/ch4_4g_as|link]] to previous work on this topic.
*The main purpose of this wiki entry is to provide insight into Dr. Gehringer's lecture on Metaprogramming in Ruby found at this [http://courses.ncsu.edu/csc517/common/media/08/Metaprogramming/Metaprogramming.html link]




Line 6: Line 7:


The most basic definition of metaprogramming is: ''writing code that writes or manipulates code.''
The most basic definition of metaprogramming is: ''writing code that writes or manipulates code.''
<ref>[http://courses.ncsu.edu/csc517/common/media/08/Metaprogramming/Metaprogramming.html Video Lecture on Metaprogramming by Dr. Gehringer]</ref>
<ref name="Video Lecture on Metaprogramming by Dr. Gehringer">[http://courses.ncsu.edu/csc517/common/media/08/Metaprogramming/Metaprogramming.html Video]</ref>
<ref name="wiki metaprogramming">[http://en.wikipedia.org/wiki/Metaprogramming Wikipedia Article on Metaprogramming]</ref>
<ref name="wiki metaprogramming">[http://en.wikipedia.org/wiki/Metaprogramming Wikipedia Article on Metaprogramming]</ref>


Line 31: Line 32:
::*Modify existing classes and/or methods at runtime
::*Modify existing classes and/or methods at runtime
::*Respond to calls made on non-existent methods
::*Respond to calls made on non-existent methods


== Features in Ruby that Enable Metaprogramming ==
== Features in Ruby that Enable Metaprogramming ==
Line 44: Line 46:


::Most object-oriented programming languages adhere to the [http://en.wikipedia.org/wiki/Open/closed_principle#Meyer.27s_Open.2FClosed_Principle open/closed principle]<ref>[http://en.wikipedia.org/wiki/Open/closed_principle#Meyer.27s_Open.2FClosed_Principle Wikipedia Article on the Open/Closed Principle]</ref>.  This means that the core components that are part of the language cannot be modified.  In Ruby, the classes are open, meaning that all of the classes and methods be changed.
::Most object-oriented programming languages adhere to the [http://en.wikipedia.org/wiki/Open/closed_principle#Meyer.27s_Open.2FClosed_Principle open/closed principle]<ref>[http://en.wikipedia.org/wiki/Open/closed_principle#Meyer.27s_Open.2FClosed_Principle Wikipedia Article on the Open/Closed Principle]</ref>.  This means that the core components that are part of the language cannot be modified.  In Ruby, the classes are open, meaning that all of the classes and methods be changed.
== Examples of Metaprogramming in Ruby <ref>[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf]Dr. Gehrenger's notes on Metaprogramming</ref>==
Ruby has several metaprogramming facilities.  One can create new class and add methods to it using "define_method"
  c = Class.new
  c.class_eval do
    define_method :hi do
    puts "Hey"
    end
  c.new.hi
  >>Hey


This technique allows you to add any type of new code and modify behavior of a program at run time.
 
Another example, adding attr_accessor to all classes:
== Examples of Metaprogramming in Ruby ==
  Object.class_eval do
 
     class << self
=== Creating a New Class at Runtime ===
       def attribute_accessor( *instance_variables )  
Below is an example of creating a new class at runtime:<ref name="DrGCodeNotes">[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf Dr. Gehrenger's notes on Metaprogramming]</ref>
        instance_variables.each do |instance_variable|
  <code>3.times do
          class_eval %Q?
      class MyClass
            def #{instance_variable}
        puts "MyClass defined"
                @#{instance_variable}
      end
            end
  end</code>
            def #{instance_variable}=( new_value )
In example shown above, the <tt>times</tt> method is invoked on the <tt>3</tt> object.  Inside of the <tt>times</tt> method call, the class <tt>MyClass</tt> is defined.  <tt>MyClass</tt> is actually defined three times, once for each of the three iterations.  Even though the class is defined three times, it has the same effect as only defining it once.  The important thing to note here, is that a new class is defined at runtime, inside of a method call.
                @#{instance_variable} = new_value
 
            end
 
           ?
=== Modifying a Class at Runtime ===
Below is an example of modifying a class, and and example of creating a new method at runtime:<ref name="DrGCodeNotes">[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf Dr. Gehrenger's notes on Metaprogramming]</ref>
  <code>3.times do
      class MyClass
        def one
            puts "one"
      end
  end</code>
In the example shown above, the class <tt>MyClass</tt> is modified again to include a new method.  This method, the <tt>one</tt> method is defined three times, just like the class is defined three times.  Even though it has been defined three times, it has the same effect as only defining it once.  The important thing to note here is that a new method is defined at runtime.
 
 
=== Creating a Method at Runtime ===
Below is an additional example of modifying a class at runtime:<ref name="DrGCodeNotes">[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf Dr. Gehrenger's notes on Metaprogramming]</ref>
     <code>class MyClass
      def two
        puts "two"
  end</code>
In the example shown above, the class<tt>MyClass</tt> is reopened and the <tt>two</tt> method is added to it.
 
 
Below is an example of what happens when the code written above is executed:<ref name="DrGCodeNotes">[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf Dr. Gehrenger's notes on Metaprogramming]</ref>
  <code>
  mc = MyClass.new
  mc.one
  mc.two
  </code>
The output of the code will be:
  <code>one
  two</code>
 
 
=== Modifying a Method at Runtime ===
 
Below is an additional example of modifying a method at runtime:<ref name="DrGCodeNotes">[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf Dr. Gehrenger's notes on Metaprogramming]</ref>
    <code>class MyClass
       def two
        puts "one two"
  end</code>
In the example shown above, the <tt>two</tt> method is reopened and modified.
 
 
Below is an example of what happens when the modified code written above is executed:<ref name="DrGCodeNotes">[http://courses.ncsu.edu/csc517/common/lectures/notes/ol5.pdf Dr. Gehrenger's notes on Metaprogramming]</ref>
  <code>
  mc = MyClass.new
  mc.one
  mc.two
  </code>
The output of the code will be:
  <code>one
  one two</code>
 
=== Responding to a Non-Existent Method Call ===
Whenever a call to an undefined method is made on an object, Ruby provides an option to intercept the call. This is done by implementing the method method_missing within the class definition.  Ruby passes, as parameters, the name of the method called and the arguments passed to it. 
 
Define a module (or class) Roman.  This class contains a method_missing method that intercepts calls to “class methods” that are undefined.  It then tries to interpret the method name as a Roman numeral.
For example,
*evaluating Roman.xix calls the xix,method of module Roman. 
*Roman has no xix method, so method_missing is invoked with xix as the argument.  
*The id2name method of class Symbol is invoked on :xix, returning "xix".
*The "xix" is then parsed according to the rules for evaluating Roman numerals, and evaluates to 19.
 
  class Roman
  DIGITS = {
    'I' => 1,
    'V' => 5,
    'X' => 10,
    'L' => 50,
    'C' => 100,
    'D' => 500,
    'M' => 1000,
  }
  def roman_to_integer(roman_string)
    last = nil
   
  roman_string.to_s.upcase.split(//).reverse.inject(0) do
  |memo, digit|
      if digit_value = DIGITS[digit]
        if last && last > digit_value
          memo -= digit_value
        else
           memo += digit_value
         end
         end
  last = digit_value
       end
       end
     end  
  memo
   end  
     end
   end
  def method_missing(method)       
    str = method.id2name
    roman_to_integer(str)     
  end
 


== Metaprogramming in Other Languages ==
== Metaprogramming in Other Languages ==
Line 98: Line 178:
   }
   }


=====The MIN macro: =====
===Meta Programming in Java<ref>[http://www.cs.tut.fi/~kk/webstuff/MetaProgrammingJavaKalvot.pdf Metaprogramming in Java]</ref>===
  #define MIN(x, y) ((x) > (y) ? (y) : (x))
 
The generics can be used in classes, interfaces, methods and constructors.
Two new types:
*Parametrized types
*Type variables
A type variable is an unqualified identifier.
Class and interface declarations can have type arguments (type variables)
*Metalevel: Class implements GenericsDeclaration
Method and constructors definitions can have type arguments (type variables)
*Metalevel: Method, Constructor implements GenericsDeclaration


This macro returns the the minimum of two values.
  public interface List<E> {
    void add(E x);
    Iterator<E> iterator();
  }
  public interface Iterator<E> {
    E next();
    boolean hasNext();
  }
  List<String> anExample;
  anExample.add(”sdfdfss”);
  anExample.add(new Object()); // compile time error
  String aTest = anExample.iterator().next();


== References ==
== References ==
<references/>
<references/>

Latest revision as of 04:22, 26 February 2013

  • Here is a link to the writing assignment for this topic.
  • Here is a link to previous work on this topic.
  • The main purpose of this wiki entry is to provide insight into Dr. Gehringer's lecture on Metaprogramming in Ruby found at this link


A Basic Definition of Metaprogramming

The most basic definition of metaprogramming is: writing code that writes or manipulates code. <ref name="Video Lecture on Metaprogramming by Dr. Gehringer">Video</ref> <ref name="wiki metaprogramming">Wikipedia Article on Metaprogramming</ref>

A metaprogram can either manipulate itself, or it can manipulate some other program.

Below are three important terms associated with a metaprogramming<ref name="wiki metaprogramming">Wikipedia Article on Metaprogramming</ref>:
  • metalanguage - the language in which a metaprogram is written
  • object language - the language of the program that is being manipulated by a metaprogram
  • reflection - the ability of a programming language to be its own metalanguage (also known as reflexivity)


Uses of Metaprogramming

Metaprogramming can allow programmers to write code that is more concise and more flexible. It can be more concise because a program that can write code is able to generate more code than it is initially given. It can be more flexible, because it can allow the program to change the way it behaves without having to recompile.

One of the best examples of metaprogramming is that of the compiler<ref>Overview of Metaprogramming</ref>. A compiler uses code written in one language in order to generate code that can be executed by a computer.
Metaprogramming is also used for building frameworks such as Ruby on Rails. In this case, the use of convention over configuration allows developers to write more concise and consistent code. Following specific conventions, developers write a relatively small amount of code. The Ruby on Rails scaffold uses the code the code written by the developer to generate code that is expansive, interconnected, and standardized.
One of the most powerful uses for metaprogramming, is the ability to change a program during runtime. In languages such as Ruby and Groovy, programmers can<ref>Coding Insights Blog</ref>:
  • Create a new class at runtime
  • Create new methods at runtime
  • Modify existing classes and/or methods at runtime
  • Respond to calls made on non-existent methods


Features in Ruby that Enable Metaprogramming

In dynamically typed languages, the majority of its type checking is performed at run-time, as opposed to compile time.<ref>Wikipedia Article on the Type System</ref> Because variables are not type-checked until they are used in program execution, it is possible to use types that are created during program execution.
Interpreted languages avoid explicit compilation<ref>Wikipeida Article on Interpreted Language</ref>. Because Ruby is being interpreted as it is being executed, it is possible to create new classes and methods during program execution.
  • Ruby classes are open
Most object-oriented programming languages adhere to the open/closed principle<ref>Wikipedia Article on the Open/Closed Principle</ref>. This means that the core components that are part of the language cannot be modified. In Ruby, the classes are open, meaning that all of the classes and methods be changed.


Examples of Metaprogramming in Ruby

Creating a New Class at Runtime

Below is an example of creating a new class at runtime:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>

  3.times do
     class MyClass
        puts "MyClass defined"
     end
  end

In example shown above, the times method is invoked on the 3 object. Inside of the times method call, the class MyClass is defined. MyClass is actually defined three times, once for each of the three iterations. Even though the class is defined three times, it has the same effect as only defining it once. The important thing to note here, is that a new class is defined at runtime, inside of a method call.


Modifying a Class at Runtime

Below is an example of modifying a class, and and example of creating a new method at runtime:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>

  3.times do
     class MyClass
        def one
           puts "one"
     end
  end

In the example shown above, the class MyClass is modified again to include a new method. This method, the one method is defined three times, just like the class is defined three times. Even though it has been defined three times, it has the same effect as only defining it once. The important thing to note here is that a new method is defined at runtime.


Creating a Method at Runtime

Below is an additional example of modifying a class at runtime:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>

   class MyClass
     def two
        puts "two"
  end

In the example shown above, the classMyClass is reopened and the two method is added to it.


Below is an example of what happens when the code written above is executed:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>

  
  mc = MyClass.new
  mc.one
  mc.two
  

The output of the code will be:

  one
  two


Modifying a Method at Runtime

Below is an additional example of modifying a method at runtime:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>

   class MyClass
     def two
        puts "one two"
  end

In the example shown above, the two method is reopened and modified.


Below is an example of what happens when the modified code written above is executed:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>

  
  mc = MyClass.new
  mc.one
  mc.two
  

The output of the code will be:

  one
  one two

Responding to a Non-Existent Method Call

Whenever a call to an undefined method is made on an object, Ruby provides an option to intercept the call. This is done by implementing the method method_missing within the class definition. Ruby passes, as parameters, the name of the method called and the arguments passed to it.

Define a module (or class) Roman. This class contains a method_missing method that intercepts calls to “class methods” that are undefined. It then tries to interpret the method name as a Roman numeral. For example,

  • evaluating Roman.xix calls the xix,method of module Roman.
  • Roman has no xix method, so method_missing is invoked with xix as the argument.
  • The id2name method of class Symbol is invoked on :xix, returning "xix".
  • The "xix" is then parsed according to the rules for evaluating Roman numerals, and evaluates to 19.
 class Roman 
 DIGITS = {
   'I' => 1,
   'V' => 5,
   'X' => 10,
   'L' => 50,
   'C' => 100,
   'D' => 500,
   'M' => 1000,
 }
 def roman_to_integer(roman_string)
   last = nil
   
 roman_string.to_s.upcase.split(//).reverse.inject(0) do
 |memo, digit|
     if digit_value = DIGITS[digit]
       if last && last > digit_value
         memo -= digit_value
       else
         memo += digit_value
       end
 last = digit_value
     end
 memo
   end
 end
 def method_missing(method)        
   str = method.id2name 
   roman_to_integer(str)      
 end


Metaprogramming in Other Languages

The C preprocessor (CPP)<ref>The Art of Metaprogramming</ref>

First let's look at metaprogramming that involves textual macro languages. Textual macros are macros that directly affect the text of the programming language without knowing about or dealing with the meaning of the language.

The SWAP macro:
  #define SWAP(a, b, type) { 
      type __tmp_c; c = b; b = a; a = c; 
  }

This macro allows you to swap the two values of the given type. A macro is effective in this situation because:

  • A function call would take too much overhead for a simple operation
  • The functions would require variables' addresses to be passed which is messier and prevents the compiler from keeping the values in registers.
  • A different function would need to be coded for each type of item you wanted to swap.


 #define SWAP(a, b, type) { type __tmp_c; c = b; b = a; a = c; }
 int main()
 {
     int a = 3;
     int b = 5;
     printf("a is %d and b is %d\n", a, b);
     SWAP(a, b, int);
     printf("a is now %d and b is now %d\n", a, b);
     return 0;
 }

Meta Programming in Java<ref>Metaprogramming in Java</ref>

The generics can be used in classes, interfaces, methods and constructors. Two new types:

  • Parametrized types
  • Type variables

A type variable is an unqualified identifier. Class and interface declarations can have type arguments (type variables)

  • Metalevel: Class implements GenericsDeclaration

Method and constructors definitions can have type arguments (type variables)

  • Metalevel: Method, Constructor implements GenericsDeclaration
 public interface List<E> { 
   void add(E x);
   Iterator<E> iterator();
 }
 public interface Iterator<E> { 
   E next();
   boolean hasNext();
 }
 List<String> anExample;
 anExample.add(”sdfdfss”);
 anExample.add(new Object()); // compile time error
 String aTest = anExample.iterator().next();

References

<references/>