CSC 123/252 Study Guide to the final exam. The final exam will be targeted to be about 1-1.5 hours in length. It will focus on the recent material but may include some questions on earlier subjects.So study the midterm as well. There will be an emphasis on F# and AspectJ There will be an emphasis on writing code fragments. ==Topics: Statically type-safe languages. Basic OOP concepts (dynamic dispatch). Polymorphism, different kinds (natural vs. artificial), how to implement in C#, relationship to type safety. F#/ML programming, including: polymorphic type inference type definitions (as in type 'a list = Nil | Cons of ('a*'a list);;) pattern matching writing small code fragments Differences with C# Features will reflect those emphasized in class, used in assignments. **Understand the relationship between F# pattern matching and dynamic dispatch and the visitor design pattern. AOP/AspectJ programming pointcut expressions (call/execute,cflow, etc...) writing advice intertype declarations and other technical features emphasized in class. Understand AOP keywords such as cross-cutting, weaving, join-points. Don't just memorize the definitions. Understand their purpose. There could also be a question that ties everything we've learned this semester together, something that concerns everything we've learned about languages, types, abstraction, oop, polymorphism, etc... ---------------------------------------------------------------------------- How to Study: Do the sample problems here without looking at the answer. Do NOT memorize definitions or simply learn the mechanics without understanding their purpose. ---- Sample questions to prepare for the final exam ---- Answers posted separately 1. Compare the following implementations of polymorphic linked lists: class list { Object head; list tail; } class list { A head; list tail; } What are the advantages of using one form instead of another? 2. Given the F# definition of a polymorphic linked list structure: type 'a llist = NIL | Cons of ('a*'a llist); What would be the closest equivalent definition in C#. Defend your answer. 3. C# allows functions to be overloaded based on the type of their parameters (and return type). Consider the following functions: void f(int x) { Console.WriteLine(" int version"); } void f(string x) { Console.WriteLine(" string version "); } Now determine what will happen with the following code (assume it's inside another method of the same class) object x = "abc"; // valid, since strings are objects f(x); // Describe what happens here. 4. Write a function in F# to compute n! (e.g., 4! = 4*3*2*1 = 24; 0!=1). You must use pattern matching (no if-else, no loops). 5. Lists in F# are written as [a;b;c], which is the same as (a::b::c::[]) Write a function to return the length of the list, without using "if" 5b. What would be the type inferred by F# for your function? 6. (a bit harder) Suppose I entered: let f x y = x;; in F# (equivalently let f = fun x -> fun y -> x;;) What will be type of f inferred by the system? 6b. Assume that F# inferred that the type of a function is ('a -> int). What does this mean with respect to polymorphism? What is an example of a function that will have such a type? Sample AspectJ problems: 7. Assume that classes C and D both have a function void f(int). Write a pointcut expression that picks out calls to either function. Also capture the argument passed. 8. Given class: class B { private int x; pubilc B(int x0) { x=x0; } // 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)); } } a. Write a pointcut that picks out the "execution" of the constructor of B. (when the constructor is called, the object doesn't exist yet). b. Write a pointcut that picks out the initial call to f (as opposed to recursive calls). c. 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 three problems that need to be addressed). d. Write an advice that throws an error if the g function is called from anywhere except main (public static void *.main(..)) f. Suppose an aspect contains the following intertype declarations: Aspect importantaspect { public int B.y; private int B.z; ... Explain the difference between public and private above (hint: they're not the same as public/private within an ordinary class). That is, what are the consequences with respect to other parts of the program. 9. Explain the difference between "withincode" and "cflow" pointcuts. 10. Explain the difference between the "this" and "target" pointcuts. The best way to answer this question is by using a specific example. ----- more questions... 11. (hard) Given type expr = Var of string | Plus of (expr*expr) | Times of (expr*expr);; let sample = Plus(Times(Var("a"),Var("b")),Times(Var("a"),Var("c"))); // sample is (a*b)+(a*c) Write a F# program to factor (a*b)+(a*c) into a*(b+c). You need to do this recursively and factor all expressions inside-out. The following tostring function can be used to test your function: let rec tostring = function | Var(s) -> s | Plus(a,b) -> "(" + tostring(a) + " + " + tostring(b) + ")" | Times(a,b) -> "(" + tostring(a) + " * " + tostring(b) + ")";; // + can also be used for string concatenation in F# printf "before factoring: %s\n" (tostring(sample)); Please note that F# does not allow you to use the same variable twice in a pattern: match x with | Plus(a,a) -> // is not ok match x with | Plus(a,b) when a=b -> is ok. 11b. How would you write this program in C#? What advantages (in general) does F# have over the dynamic dispatch/oop approach? 12. Explain in your own words one advantage of parametric polymorphism over inheritance polymorphism. That is, what's the difference between using a type parameter , and calling your variables (for example) "A x" instead of "object x". 13. (a bit harder) C# and Java do not allow multiple inheritance of classes, only of interfaces, but we want to do it anyway. Suppose interface Ia { void f(); } interface Ib { void g(); } class A : Ia { ... } class B : Ib { ... } Suppose the constructors of A and B are invoked as in new A() and new B(). Write a class that inherits both the A and B objects, and can call f and g: