CSC/ECE 517 Spring 2013/ch1b 1k hf: Difference between revisions
Line 209: | Line 209: | ||
=== | ===Meta Programming in Java<ref>[http://www.cs.tut.fi/~kk/webstuff/MetaProgrammingJavaKalvot.pdf 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 == | ||
<references/> | <references/> |
Revision as of 04:17, 21 February 2013
- Here is a link to the writing assignment for this topic.
- Here is a link to previous work on this topic.
A Basic Definition of Metaprogramming
The most basic definition of metaprogramming is: writing code that writes or manipulates code. <ref>Video Lecture on Metaprogramming by Dr. Gehringer</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
- Ruby is a dynamically typed language
- 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.
- Ruby is an interpreted language
- 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. Another interesting use of method_missing can be found on the Web by looking for “Roman method_missing”. 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
Ruby has several metaprogramming facilities. One can create new class and add methods to it using "define_method"<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>
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:<ref name="DrGCodeNotes">Dr. Gehrenger's notes on Metaprogramming</ref>
Object.class_eval do class << self def attribute_accessor( *instance_variables ) instance_variables.each do |instance_variable| class_eval %Q? def #{instance_variable} @#{instance_variable} end def #{instance_variable}=( new_value ) @#{instance_variable} = new_value end ? end end end 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; }
The MIN macro:
#define MIN(x, y) ((x) > (y) ? (y) : (x))
This macro returns the the minimum of two values.
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/>