# CSC 123/252 Scary Test # A scary test will make you study really hard for the real test. # Answer each question carefully. The test will be "graded". #1. Explain the difference between the C# functions f and g below: Func f() { return (d0) => { int y=0; y+=d0; return y; }; } Func g() { int y=0; return (d0) => { y+=d0; return y; }; } #Determine the output of var f1 = f(); var g1 = g(); Console.WriteLine(f1(1)+f1(1)); // 2 Console.WriteLine(g1(1)+g1(1)); // 3 The key difference is that returns a lambda term with a free variable, i.e. a proper closure. g1 changes a variable in its environment and is therefore "stateful", meaning that g1(1) will return different values each time it's called. 1b. which of the above functions can be written in C? Explain. Only f can be emulated in C. The int y=0 in g() will get popped from the stack. 2. Someone has invented a new language called C** that's claimed to be the best ever. The syntax certainly looks familiar: int x = 1; // declares and initializes global variable int f(int y) { return y+1; } // define function with argument y void MAIN() // MAIN must be in all capitals (ingenious!) { int x = 2; // declares "local" variable inside main stdout << f(x) << endl; // fantastic new way to print! // this will print 3 in C** } But you didn't find any documentation on whether this language uses static or dynamic {\bf scoping.} Devise an experiment (write a program in C**) to find out. That is, write one program that will behave differently depending on the scoping rule used. Be clear as to how to interpret the result of your experiment. The existing program is not able to distinguish between the two forms of scoping because the function f does not contain any free variables. int x = 1; // declares and initializes global variable int f(int y) { return y+x; } // define function with argument y void MAIN() // MAIN must be in all capitals (ingenious!) { int x = 2; // declares "local" variable inside main stdout << f(0) << endl; // fantastic new way to print! // this will print 3 in C** } // this program will print 1 for static scoping and 2 for dynamic scoping. // the scoping rule concerns where to find the values of FREE variables. dynamic // scoping takes the nearest x at runtime, which static scoping at compile time: that // is, the x that f refers to is already determined at compile time. 3. Explain why or why won't the following JAVA generic class compiles class A { static T x; } // will this compile? won't compile because Java uses type erasure to implement generics. static means there's only one copy of the variable for all instances of the class. But it should be a different variable for A than for A, which is not distinguished with type erasure. 4. Explain why object[] A = new string[4]; should not compile (regardless of whether it does) A[0] = 3.5; // compiles. (though it would give a runtime error) arrays should not be covariant: think of the type object[] as Array. To be covariant, the type object can only appear as an "out" type (a return type), and never as an "in" type (argument type). But this is not possible with all the operations that we need on arrays (get as well as set). Covariant arrays were allowed because, before generics, it was the only way to write polymorphic algorithms such as those for sorting arrays. 5. Determine the output of the following C# program class A {} class B : A {} public class goodquestion { public int f(A x) { return 1; } public int f(B x) { return 2; } public static void Main() { A n = new B(); goodquestion gq = new goodquestion(); System.Console.WriteLine( gq.f(n) ); // outputs 1 }//main } Forgot to ask you to EXPLAIN WHY: this is overloading, not overriding. Overloading is resolved at compile time (static versus dynamic dispatch). To the compiler, the type of n is A, not B, which is only created at runtime. So the compiler will choose the version of f that takes an A object.