CSC 123/252 Nightmare Test You just found out that the programming languages final is TODAY! You must fight back the panic and do the best you can ... 0. Select all true statments: a. Rust does not have exceptions because exceptions are dynamically scoped b. Rust always guarantees tail-recursion optimization c. C++ can still have memory leaks even with the exclusive use of unique_ptr and make_unique (no raw pointers) d. In a Rust expression of the form `n.f()`, dynamic dispatch is always used to determine which function f to call on object n. f. It is not possible to have a memory leak in Rust. g. Rust will automatically move values from stack to heap in order to extend their "lifetime", just like the language Go. h. Calling .unwrap on an Option in Rust can result in panic (crash). i. Rust is not as strongly type checked at compile time as F# WARNING: selecting certain items may result in a score of zero regardless of what else was selected. 1. Determine what, if anything, is wrong with the following C++ program: template struct Bst { T item; unique_ptr> left{nullptr}; unique_ptr> right{nullptr}; Bst(T i) : item{i} {} Bst(T i, unique_ptr>&& l, unique_ptr>&& r) : item{i} { left = move(l); right = move(r); } static unique_ptr> maketree(int i) { auto tree = make_unique>(5); tree->left = move(tree); return tree; } }; 2. Given a language, such as lambda7b or F#, that allows for arbitrary mutations and where both call-by-name and call-by-value is possible. Write a program that will return different values depending on call-by-name or call-by value 2b. Write the same program in the syntax of Rust. How would Rust handle the situation? Will it compile? Why or why not? 3. Consider the following program in traditional C++: template void bubblesort(T* a, int len) { for(int i=0;i+1 a[k+1]) { T temp = A[k]; A[k] = A[k+1]; A[k+1] = temp; } } // for k }//for i }//bubblesort }; Rewrite the program in modern C++ using smart pointers. Furthermore, do not assume that type T can be copied. 4. Java has the following interface (java.util.function.Function): interface Function { B apply(A x); } Explain what, if anything, is wrong with the following function: U apply_fun(T x, Function fun) { return fun.apply(x); } ? extends T means some type that could be T or a subclass of T, ? super U means some type that could be U or a superclass of U. 5. What is the expected behavior of the following Rust program. Will it compile? Why or why not? fn main() { let mut v = vec![1,2,3,4]; for x in v.iter() { v.push(*x); } } 5b. What about in C++: int main() { vector v{1,2,3,4}; for(auto x:v) v.push_back(x); } 6. Determine if the following program in Rust would compile: fn main() { let mut v = vec![1,2,3,4]; v[0] = v[v.len()-1]; } 7. How about the following: fn intersection(a:&Vec, b:&Vec) -> Vec<&T> { let mut intersect = Vec::new(); for x in a { if b.contains(x) { intersect.push(x); } } intersect } 7b. If the above doesn't compile, make minimal changes to the program so that it would compile. 8. In Rust, `std::env::args()` returns an Iterator over the command-line arguments, as owned Strings, passed to main. std::evn::args().nth(1) will give you the first argument, if it exists. It returns an Option. Give a string (or slice) s, `s.parse::()` will attempt to convert the string into an unsiged integer that can be used as a size or index. It will return a Result. For example, "12".parse::() will return Ok(12) and "abc".parse:: will return Err(e) where e is a ParseIntError object (when printed, it will say "error invalid digit found in string"). The following code was written by someone who was terrible at monadic error handling (though it compiles). fn main() { let mut n = 100; // default value of n, to be changed by command-line arg let option1 = std::env::args().nth(1); if option1.is_some() { let string1 = option1.unwrap(); let result1 = string1.parse::(); if result1.is_ok() { n = result1.unwrap(); } } // ... } 8a. Rewrite the above with pattern matching. You may not call is_some/is_ok or unwrap/unwrap_or. 8b. Rewrite the above using only .map and/or .and_then. No more than two calls are allowed (two .map/.and_then). For this one you may also call .unwrap_or. 9. Given the following implementation of linked lists in Rust: struct Cell { item : T next : Option>>, } impl Cell { ... Write a function under this impl that returns the length of a list (represented by a cell). 10. Given a trait called Shape, explain the difference between fn get_area(s:&T) -> f64 { s.area() } and fn calc_area(s:&dyn Shape) -> f64 { s.area() } You finally wake up and realize that it's only a nightmare. The real test is Monday...