CSC/ECE 517 Fall 2011/ch4 4g ms

From Expertiza_Wiki
Revision as of 22:41, 20 October 2011 by Schavva (talk | contribs)
Jump to navigation Jump to search

What is Metaprogramming?

Metaprogramming can change the way you program in your programming language. This is the most under used programming techniques is writing programs that generate programs ro program parts. Metaprogramming is writing computer programs that manipulate other programs or that which do a part of their work at compile time that would otherwise be done at runtime. This is very advantageous because it gives greater flexibility to programs to efficiently handle new situations without recompilation. Languages which provide metaprogramming are called metalanguages. Metaprograms treat themselves as part of data and they can modify their own structure and behaviour.

History of Metaprogramming:

Not all metaprogramming involves generative programming. If programs are modifiable at runtime or if an incremental compilation is available, then techniques can be used to perform metaprogramming without actually generating source code. Template metaprogramming is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates include compile-time constants, data structures, and complete functions. In C-language, one of the popular examples of meta-programming is the Lex/Yacc system for generation of parsers and lexical scanners. That is, it reads an input stream specifying the lexical analyzer and outputs source code implementing the lexer in C. Instead of doing the laborious work of generating a parser in C, one can use Yacc to generate the repetitive parts of the program. Then, one can add only the code necessary to operate on the parsed entities. Metaprogramming in Java comprises of three main components reflection, generics, annotations.

Uses of Metaprogramming:

  • Metaprogramming allows us to write programs that will pre-generate tables of data for use at runtime. For example, if a quick lookup table for the sine of all 8-bit integers is needed, then the sin can either be calculated and hand coded or the program can be made to build the table at startup at runtime or a program can used to build the custom code for the table before compile-time. While it may make sense to build the table at runtime for such a small set of numbers, other such tasks may cause program startup to be prohibitively slow. In such cases, writing a program to build static data tables is usually the best answer.
  • A mini language can be created when there are a lot of functions which include a lot of boilerplate code. This mini language will do the boilerplate code and lets the user code only the important parts.

It is best to abstract out the boilerplate portions into a function. But often the boilerplate code isn't so pretty. Maybe there's a list of variables to be declared in every instance, or maybe there are several pieces of the boilerplate that have to have code inserted in certain circumstances. All of these make a simple function call impossible. In such cases, it is often a good idea to create a mini-language that allows the developer to work with the boilerplate code in an easier fashion. This mini-language will then be converted into your regular source code language before compiling. Finally, a lot of programming languages make the developer write really verbose statements to do really simple things. Code-generating programs allow the developer to abbreviate such statements and save a lot of typing, which also prevents a lot of mistakes because there is less chance of mistyping.

Examples of metaprograms are:

  • Compiler or interpreter of any language
  • Lex and Yacc
  • CORBA's IDL compiler
  • Quine
  • Programs to generate EJB code and XML from database metadata
  • Enhanced Cweb.


Aliasing:

We can redefine a method in an existing class by opening it up and rewriting it, but since we cannot loose the behaviour provided by the original method, we can use alias_method. alias :new :old alias_method :new, :old

Syntax:

alias method-name method-name alias global-variable-name global-variable-name

Creates a new reference to whatever old referred to. old can be any existing method, operator, global. It may not be a local, instance, constant, or class variable. Alias_method is used when there is a need to override a method but still count on its old behaviour.

Example1:

alias foo bar  Creates a foo alias for bar alias $MATCH $&  $MATCH is an alias for $&


Example2:

1. def oldmtd 2. "old method" 3. end 4. alias newmtd oldmtd 5. def oldmtd 6. "old improved method" 7. end 8. puts oldmtd 9. puts newmtd

The output is: 1. old improved method 2. old method


Local variables, instance variables, class variables and constants may not be aliased. The parameters to alias may be names or symbols. When a method is aliased, the new name refers to a copy of the original method’s body. If the method is subsequently redefined, the aliased name will still invoke the original implementation. Aliases cannot be defined within the method body. The alias of the method keeps the current definition of the method even when the methods are overridden. Making aliases for the numbered global variables ($1,$2,….) is prohibited. Overriding the built in global variables may cause serious problems.


Modules:

Module is just a bunch of instance methods. A class is just a module but has certain additional features like a superclass and a new() method. The main reason for having both modules and class in Ruby is to make the code more explicit. A module is used in situations where it has to be included somewhere or when it needs to be used as a namespace. A class is used when it needs to be instantiated or inherited. A module can be included by a class. A module can be shared between and included by multiple classes at the same time. Modules can be used to organize constants in the same way as directories are used to organize files. Example module Stats

 def max_health
   100
 end
 def constitution
   50
 end

end


class Character

 include Stats
 attr_accessor:name
 attr_accessor:location
 def talk; end
 def walk; end

end


In the above example we have extracted max_health and constitution into a module. The Character class incudes the Stats module. Whenever a method is called on an instance of Character, that cannot be found in the referenced class, Ruby will look if the method can be found in one of the included modules. This is not the same as inheritance. Multiple modules can be included at the same time.

Modules define a namespace, a sandbox in which your methods and constants can play without having to worry about being stepped on by other methods and constants.

include mixes a module into a class or another module. Methods from that the module are called function-style (without a receiver).

Extend keyword can be used to extend a single functionality for the object. Adds to object the instance methods from each module given as a parameter.


module Mod

 def hello
   "Hello from Mod.\n"
 end

end

class Klass

 def hello
   "Hello from Klass.\n"
 end

end

k = Klass.new k.hello » "Hello from Klass.\n" k.extend(Mod) » #<Klass:0x401b598c> k.hello

extend is used to include a module in an object(instance). Methods in the module become methods in the object

The possibilities meta programing opens up seem to be endless. Joining on the way are endless possibilities to do something wrong. “with great power comes great responsibility”