CSC 123/252 Scary Test A scary test will make you study really hard for the real test. Answer each question carefully. Give yourself about 1hr minutes to complete the test. 1. Explain the difference between the F# functions f and g below: let f n = fun y -> let mutable x = n x <- x+y x let g n = let mutable x = n fun y -> x <- x+y x Determine the output of let f1 = f(2) let g1 = g(2) System.Console.WriteLine(f1(1)+f1(1)); // 6 System.Console.WriteLine(g1(1)+g1(1)); // 7 : g is a proper mutable closure 1b. which of the above functions can be written in C? Explain. only f, because the internal function doesn't contain free variables. In g, the local variable x will popped off the stack. 1c. Write the function g as a lambda expression in C++. You may use "auto" to infer types. auto g = [](int n){ return [n](int y) mutable { n+=y; return n;}; }; the x variable was needed in F# because the argument n is not mutable. There's no such restriction in C++, but you do need to lable the closure as mutable. 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! { int x = 2; // declares "local" variable inside main stdout << f(2) << 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 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. Be clear as to how to interpret the result of your experiment. This program can't make the distinction between static versus dynamic scoping because the function f contains no free variables. Change f to int f(int y) { return x; } Now it will print 1 under static scoping and 2 under dynamic scoping. 3. Explain why or why won't the following JAVA generic class compile class A { static T x; T[] = new T[10]; } // will this compile? will not compile because java uses type erasure to implement generics, but A and A require two distinct x variables, one of type Integer and one of String. But type erasure means they can only have one type: Object. 4. Explain why object[] A = new string[4]; should not compile (regardless of whether it does) Because the type of the array cannot get smaller (covariant), because it has to implicity cotain a void set(int index, object x): it has to be able to take ANY object as argument, you cannot shrink x to a string. A[0] = 1.2; // will compile because the static type of A[0] is object. 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) ); // 1 because this is overloading, // and resolved by the compiler }//main } 6. In F#, int(s) will convert string s into an integer and throw an exception if s can't be converted. 6a. Write a function safeint that returns a value of type `int option`: That is, Some(n) where n is an int, or None. The exception should be caught internally and not allowed to escape the function. Hint the syntax of a "try-with block" in F# is: try stuff with | e -> expression to return, must match type of "stuff" let safeint(s:string) = try Some(int(s)) with | e -> None 6b. write a function that takes a string, calls safeint on the string, and either print the integer that was parsed or print "invalid input" if it can't be parsed. You're not allowed to call Option.get. let getint(s:string) = match (safeint s) with | Some(n) -> printfn "%d" n | None -> printfn "invalid format" let opt = safeint(s) if Option.isNone(opt) then ... print invalid else Option.map (fun x -> printf "%d" x) opt A && B if (!A) return 0 else return B