Sample answers to quiz practice problems. 1. Write a pointcut to pick out attempts to access public variables of class A. pointcut access() : get(public * A.*); 2. Assume that classes C and D both have a function void f(int). Write a pointcut that picks out calls to either function. Also capture the argument passed with the pointcut. pointcut callf(int x) : (call(void C.f(int)) || call(void D.f(int))) && args(x); 3. Given class: class B { private int x; pubilc B(int x0) { x=x0; } // constructor public B() { x=1; } // default constructor public int f(int n) { if (n<2) return 1; else return n*f(n-1); } public void g(int y) { System.out.println(x+f(y)); } } 3a. Write a pointcut that picks out the "execution" of the constructors of B. execution(B.new(..)) 3b. Write a pointcut that picks out the FIRST call to f (as opposed to recursive calls). call(int B.f(int)) && !withincode(int B.f(int)) 3c. The following pointcut and advice tries to change the parameter passed to g. Explain what's wrong with it the way it's written. DON'T JUST CORRECT IT; *EXPLAIN* WHY IT'S WRONG THE WAY IT IS! before(int y) : call(void B.g(int)) && args(y) { g(y+1); } (hint: there are two problems that need to be addressed). The first problem is that a before advice won't prevent the original call from being made, unless it throws an error or exception. You won't have to write advice on the quiz but you certainly have to know how they work. The second problem is that the advice will kick in again when g is called inside, so it'll execute the advice code forever. You can prevent this from happening by using !adviceexecution() or !within(youraspect), but you can't just fix it, you need to explain it. 3d. Write a pointcut that picks out attempts to call g from within class A, capturing the argument passed, as well as the "this" and "target" objects. pointcut (A u, B v, int x) : call(void B.g(int)) && within(A) && args(x) && this(u) && target(v); Note the different types of u and v and their correspondence with u and v. If you didn't know the type of the object, you'll have to declare it as an Object when capturing it in the pointcut. 4. Explain the difference between "this" and "target" pointcuts. When a method A.f is called from B.g, then the instance of B the call is comming from is "this" object and the instance of a it's called on is the "target". Note that if f is static, there is no "target" and any pointcut that tries to capture "target" will fail. Similarly, "this" won't exist if g is static. 5. Explain the difference between withincode and cflow pointcuts. withincode is static and cflow is dynamic. if f calls g and g calls h, then withincode(*.f(..)) will not capture the call to h, but cflow(call (*.f(..))) will. 6. Explain in your own words one advantage of parametric polymorphism over inheritance polymorphism. There are many concepts involved here and many correct answers can be given. First of all, you need to understand the difference between natural polymorphism and polymorphism that can only be achieved by building a layer of abstraction. Inheritance and dynamic dispatch allows you to build abstraction (abstract away differences such as between integers and rationals). However, inheritance also means that you have to (statically) type your data with a supertype (typically Object). This means that the type consistency of your program, to a large extend, can't be determined until runtime. The role of parametric polymorphism is not clear cut. The advantage it has over the inheritance method is that it allows static type checking, using the type inference rules we talked about. However, parametric polymorphism won't allow you to *build* abstraction. That is, using a type variable alone won't resolve the differences between integer and rational equality, for example. One must still provide different algorithms. Thus parametric polymorphism is only useful in implementing routines that are already (naturally or rendered) polymorphic. In other words, in untyped languages such as Scheme or Python it's trivial to write naturally polymorphic functions. In a typed language, one still wishes to write such functions, but in a way that's consistent with the type system and its advantages. This is the dilemma that parametric polymorphism attempts to address. Please understand this - don't recite it. I will be satisfied if you only truly understand a portion of these issues, but whatever you write in response to such questions will have to be in your own words.