CSC 123/252 Nightmare Test You just found out that the programming languages final is TODAY! You want to panic! but panic! in Rust is really bad!. final_exam.map(|test|println!("good luck on {}",test)); 1. (8) Select all true statments: T a. Rust does not have exceptions because exceptions are dynamically scoped F b. Rust always guarantees tail-recursion optimization T c. C++ can still have memory leaks even with the exclusive use of unique_ptr and make_unique (no raw pointers) F 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 f. It is not possible to have a memory leak in Rust. F g. Rust will automatically move values from stack to heap in order to extend their "lifetime", just like the language Go. T h. Calling .unwrap on an Option in Rust can result in panic (crash). F i. F# is not as strongly type checked at compile time as C# WARNING: selecting certain items may result in a score of zero regardless of what else was selected. 2. 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(); } } // ... } 2a. Rewrite the above with pattern matching. You may not call is_some/is_ok or unwrap/unwrap_or. let mut n = 100; // default value of n, to be changed by command-line arg let option1 = std::env::args().nth(1); if let Some(string1) = option1 { if let Ok(result1) = string1.parse::() { n = result1; } } 2b. 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. option1.and_then(|string1|{ string1.parse::().map(|result1|{ n = result1; })}); if option1.is_some() { let string1 = option1.unwrap(); let result1 = string1.parse::(); if result1.is_ok() { n = result1.unwrap(); } } 3. The following function takes a mutable borrow of a vector and returns a vector of mutable borrows of the values of the vector. Explain why it doesn't compile (in specific terms). Do not change the function's type (signature). fn mutborrows(v:&mut Vec) -> Vec<&mut T> { let mut i = 0; let mut mv = Vec::new(); let vlen = v.len(); while (i(x:&'lt i32, y:&'lt i32) -> &'lt i32 { if *x < *y { x } else { y } } 5. Explain what, if any memory errors will result from calling the following C++ function. void cpp_forever() { int *a = new int[10]; int *b = new int[10]; a = b; // memory leak delete a; } 5b. Rewrite the function using std::unique_ptr and std::make_unique to eliminate all errors. Then EXPLAIN how the errors where eliminated: be specific to a, b in the explanation. Superfluous materials will result in lost points. { auto a = make_unique(10); unique_ptr b = make_unique(10); a = move(b); } 6. Give an example of how mixing raw pointers with unique_ptr can compromise the effectiveness of the smart pointer. Write no more than five lines of code in C++. Hint: call the unique_ptr public constructor that initializes it with a raw pointer. :RA is not I int *x = new int(1); unique_ptr a(x); unique_ptr b(x); memcpy(&a,&b, sizeof(unique_ptr)); 7. Write a C++ program to show that a memory error is still possible even with the exclusive use of unique_ptr/make_unique, with no raw pointers involved. struct node { unique_ptr A; unique_ptr next; node() { A = make_unique(10); } }; unique_ptr P = make_unique(); P->next = move(P); // causes memory leak 8. Show how to emulate dynamic scoping in a statically scoped language. Then explain how Rust prevents the emulation. let mutable x = 1; let f = fun y -> x+y; let g() = let savex = x; x <- 2; printfn "%A" (f 0) # 2 x <- savex 9. Give an example of function(s) that return different values depending of call-by-value or call-by-name. int x = 1; int f() { x = 0; return x; } int g(int y) { return x; } g(f()) CBV -> 0 CBN -> 1