CSC 123/252 Nightmare Test You partied when you should be studying and now you suddenly realize that you forgot that the programming languages final was TODAY! And the problems looks hard too, because you didn't study! 1. Explain what, if anything, is wrong with the following C# interface: interface I { A f(B x); B g(); } B is both a domain type (argument) and codomain type (return type), so can't be contravariant. in B means B can only be a argument/parameter type. 1b. Explain what, if anything, is wrong with the following code: using System.Collections.Generic; //... List N = new List; // List is similar to ArrayList in Java T get(int i) void add(T x) object x = "abc"; object[] A = new string[10]; A[0] = 2; 2. Consider the following F# code: type 'a lst = Nomore | More of ('a * 'a lst); let rec sum = function | Nomore -> 0 | More(x,cdr) -> x + sum(cdr);; 2a. Write a tail-recursive version of the sum function, or use a loop: let rec isum ax n = ///= function match n with | Nomore -> ax | More(x,d) -> isum (ax+x) d;; let sum n = let mutable ax = 0 let rec isum = function | Nomore -> () // void return | More(x,cdr) -> ax <- ax + x isum cdr isum n ax;; 3. Consider the following program interface expr // interface for abstract expression { T accept(exprvisitor v); // polymorphic function } interface exprvisitor // interface for abstract visitor { T visit(intnode e); T visit(plusnode e); T visit(timesnode e); } class intnode : expr // integer expreesion { internal int val; public intnode(int v) {val = v; } public T accept(exprvisitor v) { return v.visit(this); } } // intnode class plusnode : expr // + operator expression { public expr left, right; public plusnode(expr l, expr r) { left=l; right=r; } public T accept(exprvisitor v) { return v.visit(this); } } // plusnode class timesnode : expr // * operator expression { public left, right; public timesnode(expr l, expr r) { left=l; right=r; } public T accept(exprvisitor v) { return v.visit(this); } } // timesnode class evalvisitor : exprvisitor { public int visit(intnode e) { return e.val; } public int visit(plusnode e) { return e.left.accepth(this)+e.right.accept(this); } public int visit(timesnode e) { return e.left.accepth(this)*e.right.accept(this); } } Write an equivalent program in F# using a discriminated union. Hint: the space below should be enough... type expr = Num of int | Plus of expr*expr | Times of expr*expr;; let rec eval = function | Num(n) -> n | Plus(a,b) -> eval(a) + eval(b) | Times(a,b) -> eval(a) * eval(b);; 4. Assume you have: class A { void f(int x) {...} } class B { void g() { A a = new A(); // what is "this" a.f(1); } } The professor then says: "write an aspect with an advice that captures both the instance of of A and the instance of B involved in a call to A.f(int) from within B.g(). Print a message around the call so as to trace it." After fighting off a panic attack you were able to muster the following: aspect a { void around(A a, B b, int x) : call(void A.f(..)) && this(b) && target(a) && args(x) { System.out.println("f is being called on object "+a+ " from object "+b); System.out.println("with argument "+x); proceed(a,b,x); } } You know it's not correct, but hopefully with some further thought you can figure out how to write the appropriate pointcut expression for the advice instead of the pathetic excuse you have now ... 5. Explain what is wrong with the following advice (given class A above) aspect A { void around(A m, int x) : call(void A.f(int)) && args(x) && target(m) && !adviceexecution() && !within(A) { // m.f(x+1); proceed(m,x+1); } // advice will run forever 5b. Show how to fix the problem above 6. You wake up and realize that it's only a nightmare. The real test is next week. Reschedule the party.