// Dynamic Scoping and "Advice" // This program depends on new feature in C# that allows any function to be // defined as a lambda term. using System; public delegate void Target(); // type of functions void -> void public class aop { //Simulating dynamic scoping with static scoping int x = 1; void f() {Console.WriteLine(x);} // f must contain a free var void g() { int saved_x = x; // simulate dynamic scope: temporary value for x x = 2; f(); // now prints 2 x = saved_x; // end of dynamic scope f(); // normal behavior will print 1 because of static scoping }//g // some lambda functions (static means belongs to class) static Func fib = (n)=> { if (n<3) return 1; else return fib(n-1)+fib(n-2); }; static Funcpower = (n,m) => /* calculates n**m */ { long ax = 1; while (m-- > 0) ax *= n; return ax; }; public static void MAIN(string[] argv) //my MAIN better than your Main { Console.WriteLine(power(2,16)); Console.WriteLine(fib(10)); // should be 55 Console.WriteLine(fib(100)); //this might take a while! } // run code under OPTIMIZATION ADVICE, crosscuts multiple funcs,classes public static void advice_optimize(Target method) { Func saved_fib = fib; // SIMULATE DYNAMIC SCOPING Func saved_power = power; // change existing functions fib = (n) => { long a=0, b =1; try{ checked { // check against overflows while (--n > 0) { b=a+b; a=b-a; } // a,b = b,a+b }} catch (OverflowException ofe) { Console.WriteLine(ofe+": Fibonacci number too big for type long"); b = -1; // return special value to indicate error. } return b; }; power = (n,m) => { // compute n**m in log(m) steps long ax = 1, factor = n; while (m>0) { if (m%2==1) ax *= factor; factor = factor*factor; m = m/2; } return ax; }; method(); // call the target method power = saved_power; fib = saved_fib; }//optimization advice // tracing and parameter-check advice public static void advice_trace(Target method,bool before, bool after) { Func saved_fib = fib; // SIMULATE DYNAMIC SCOPING Func saved_power = power; int recursion_depth=0; //fine control over when advice runs fib = (n) => { if (n<1) throw new Exception("Fibonacci function undefined for "+n); else if (before && recursion_depth==0) Console.WriteLine("..calling fib on "+n); recursion_depth++; long result = saved_fib(n); // calls existing function recursion_depth--; if (after && recursion_depth==0) Console.WriteLine("..returned "+result+" from fib call"); return result; };// new fib power = (n,m) => { if (m<0) throw new Exception("function not defined for negatives"); if (before) Console.WriteLine("..calling power("+n+","+m+")"); long result = saved_power(n,m); if (after) Console.WriteLine("..power("+n+","+m+") returned "+result); return result; }; method(); power = saved_power; fib = saved_fib; }// tracing advice public static void Main(string[] argv) { (new aop()).g(); //System.Console.Out = null; // readonly property (darn!) MAIN(argv); // call my main without any advice (not advisable) //advice_trace(()=>MAIN(argv), true, false); // call under trace advice //advice_optimize( ()=>MAIN(argv) ); // call under optimization advice advice_optimize( ()=>advice_trace(()=>MAIN(argv),true,true) ); // order determines priority: innermost advice will have precedence //advice_trace( ()=>advice_optimize(()=>MAIN(argv)),true,true ); // advice applied left to right - this is called "WEAVING" //System.Console = null; // can't change a class, too bad! }//main }