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

From Expertiza_Wiki
Jump to navigation Jump to search
Line 82: Line 82:
  }
  }


== Metaprogramming in Scala ==


'''Scala''' (multiparadigm object oriented programming language) stands for "scalable languages" designed to grow with the demands of its users.
In Scala, metaprogramming can be done with different ways. Conditional compilation and loop unrolling are most common among them.
'''Conditional compilation''' is compiling code, which is excluded by a compile time condition does not have any effect on the run-time behavior of the rest of the code. That is, the rest of the code behaves exactly as if the excluded code were not there at all. It is useful for enabling or disabling debugging or logging statements. Optimizing compilers generally remove code which is unreachable. This is where meta-programming fits in: type level encoded functions i.e. meta-functions are evaluated at run-time. The result of the evaluation is a type. Now we only need to trick the compiler into compiling a block of code or not compiling it depending on that type.
'''''Example''''' [http://michid.wordpress.com/ 5]
object Booleans {
  trait BOOL {
    type a[t <: BOOL, f <: BOOL] <: BOOL
    type v = a[TRUE, FALSE]
  }
  final class TRUE extends BOOL {
    type a[t <: BOOL, f <: BOOL] = t
  }
  final class FALSE extends BOOL{
    type a[t <: BOOL, f <: BOOL] = f
  }
  trait IF[x <: BOOL, y <: BOOL, z <: BOOL] extends BOOL {
    type a[t <: BOOL, f <: BOOL] = x#a[y, z]#a[t, f]
  }
  trait NOT[x <: BOOL] extends BOOL {
    type a[t <: BOOL, f <: BOOL] = IF[x, FALSE, TRUE]#a[t, f]
  }
  trait AND[x <: BOOL, y <: BOOL] extends BOOL {
    type a[t <: BOOL, f <: BOOL] = IF[x, y, FALSE]#a[t, f]
  }
  trait OR[x <: BOOL, y <: BOOL] extends BOOL {
    type a[t <: BOOL, f <: BOOL] = IF[x, TRUE, y]#a[t, f]
  }
  // aliases for nicer syntax
  type ![x <: BOOL] = NOT[x]
  type ||[x <: BOOL, y <: BOOL] = OR[x, y]
  type &&[x <: BOOL, y <: BOOL] = AND[x, y]
}
object PreProc {
  def IF[B] = null.asInstanceOf[B]
  object Include {
    def apply(block: => Unit) {
      block
    }
  }
  object Exclude {
    def apply(block: => Unit) { }
  }
  implicit def include(t: TRUE) = Include
  implicit def exclude(f: FALSE) = Exclude
}
object IfDefTest {
  import PreProc._
  type LOG = TRUE
  type ERR = TRUE
  type WARN = FALSE
  def errTest() {
    IF[(LOG && ERR)#v] {
      println("err")
    }
  }
  def warnTest() {
    IF[(LOG && WARN)#v] {
      println("warn")
    }
  }
  def main(args: Array[String]) {
    errTest()
    warnTest()
  }
}


== Metaprogramming in Java ==
== Metaprogramming in Java ==

Revision as of 16:22, 9 October 2009

Metaprogramming

Introduction

Metaprogramming, is the creation of procedures and programs that automatically construct the definitions of other procedures and programs. Metaprogramming automates some of the tedious and error-prone parts of the programmer's job.It refers to a variety of ways a program has knowledge of itself or can manipulate itself.It's basically "writing code that writes code".

To understand metaprogramming, compiler is a very good example. It takes as input, code in some language, and creates code for another language.

The most liberal definition of metaprogramming is:

  • Compile code generation or Runtime code generation (or both)
  • Aspect-Oriented Thinking or Aspect Oriented Programming
  • DRY Thinking

Metaprogramming in various languages

There are many languages that do metaprogramming. In languages like C#, reflection is a form of metaprogramming since the program can examine information about itself. For example, returning a list of all the properties of an object. In languages like ActionScript, we can evaluate functions at runtime to create new programs such as eval("x" + i).DoSomething() would affect an object called x1 when i is 1 and x2 when i is 2.

Another common form of metaprogramming is when the program can change itself in non-trivial fashions. LISP is well known for this. The program would change another part of the program based on its state. This allows a level of flexibility to make decisions at runtime that is very difficult in most popular languages today. It is also worth noting that back in the good old days of programming in straight assembly, programs that altered themselves at runtime were necessary and very commonplace.

It can be implemented by using any of these and in combination:

  • Reflection
  • DSLs (Domain Specific Languages)
  • (.NET) or Annotations (Java)
  • Generics (.NET/Java)
  • Templates (C++)
  • Method_missing (Ruby)
  • Closures / first class functions / delegates
  • AOP - Aspect Oriented Programming
  • Conditional compilation and loop unrolling (Scala)

Metaprogramming in Ruby

We have a C program that needs to include a PNG image, but for some reason, the deployment platform can accept one file only, the executable file. Thus, the data that conforms the PNG file data has to be integrated within the program code itself. To achieve this, we can read the PNG file beforehand and generate the C source text for an array declaration, initialized with the corresponding data as literal values. This Ruby script does exactly that:

INPUT_FILE_NAME = 'ljlogo.png'
OUTPUT_FILE_NAME = 'ljlogo.h'
DATA_VARIABLE_NAME = 'ljlogo'
File.open(INPUT_FILE_NAME, 'r') do |input|
  File.open(OUTPUT_FILE_NAME, 'w') do |output|
    output.print "unsigned char #{DATA_VARIABLE_NAME}[] = {"
    data = input.read.unpack('C*')
    data.length.times do |i|
      if i % 8 == 0
        output.print "\n    "
      end
      output.print '0x%02X' % data[i]
      output.print ', ' if i < data.length - 1
    end
    output.puts "\n};"
  end
end


Metaprogramming in Groovy

Below example demonstrates using classes from the Jakarta Commons Lang package for metaprogramming. All of the methods in org.apache.commons.lang.StringUtils coincidentally follow the Category pattern — static methods that accept a String as the first parameter. This means that you can use the StringUtils class right out of the box as a Category.

import org.apache.commons.lang.StringUtils
 class CommonsTest extends GroovyTestCase{
  void testStringUtils(){
    def word = "Introduction"
    word.metaClass.whisper = {->
      delegate.toLowerCase()
    }
     use(StringUtils, StringHelper){
      //from org.apache.commons.lang.StringUtils
      assertEquals "Intro...", word.abbreviate(8)
       //from the StringHelper Category
      assertEquals "INTRODUCTION", word.shout()
       //from the word.metaClass
      assertEquals "introduction", word.whisper()
    }
  } 
}
class StringHelper{
  static String shout(String self){
    return self.toUpperCase()
  }
}


Metaprogramming in Java

Metaprogramming in Python

Python supports metaprogramming through metaclasses, decorators and descriptors.

  • Metaclasses considered as "the class of a class" enable the creation of new “types of classes” which can customize the class creation process and/or add class methods and attributes.
  • Decorators look like Scala annotations but are applied only to function definitions and yield (possibly transformed) functions.
  • Descriptors provide a very concise way to add custom properties to classes that invoke logic but syntactically manipulated as regular attributes. They can also carry extra information (such as titles, database column mappings, etc) that can be useful when accessed through relfection.

Metaprogramming in Common Lisp

Metaprogramming in MetaOcml

Metaprogramming in C++

These Metaprograms run before the load time of the code they manipulate. Precompilers: C/C++ precompiler. Open compilers: like writing transformations on AST (hygenic macros). Two level languages: C++ templates


template <int i>
struct D
{
    D(void *);
    operator int();
};
template <int p, int i>
struct is_prime
{
    enum { prim = (p%i) && is_prime<(i>2?p:0), i>::prim };
};
template <int i>
struct Prime_print
{
    Prime_print<i-1>    a;
    enum { prim = is_prime<i,i-1>::prim };
    void f() { D d = prim; }
};
struct is_prime<0,0> { enum { prim = 1 }; };
struct is_prime<0,1> { enum { prim = 1 }; };
struct Prime_print<2>
{
    enum { prim = 1 };
    void f() { D<2> d = prim; }
};
void foo()
{
    Prime_print<10> a;
}
// output:
// unruh.cpp 30: conversion from enum to D<2> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<3> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<5> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<7> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<11> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<13> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<17> requested in Prime_print
// unruh.cpp 30: conversion from enum to D<19> requested in Prime_print


Index

  • multiparadigm language : Multiparadigm languages provides a framework in which programmers can work in a variety of styles, freely intermixing constructs from different paradigms. Examples are C, C++, Java, Ruby, Oz, Visual Basic, Perl, Python etc. The design goal of multiparadigm languages is to allow programmers to use the best tool for a job, admitting that a single paradigm can not solve all problems in most efficient or easiest way.

References

1.http://www.ibm.com/developerworks/java/library/j-pg06239.html
2.http://stackoverflow.com/questions/514644/what-exactly-is-metaprogramming
3.http://aszt.inf.elte.hu/~gsd/halado_cpp/ch06s04.html
4.http://en.wikipedia.org/wiki/Multi-paradigm_programming_language#Multi-paradigm_programming_language - Multi-paradigm_programming_language