COMP6991 23T1 — Solving Modern Programming Problems with Rust

Objectives
Week 10 Weekly Exercises
Show how the final exam works.
Prac exam from 22T3, followed by real exam from 22T3
None of these are marked, but obviously will be in the real exam The 23T1 exam will likely have 7 questions instead of 8
Activities To Be Completed
The following is a list of all the activities available to complete this week…
The following practice activities are optional and are not marked, or required to be completed for the week.
Exam Preamble Q1
22T3 Q1: Theory (10 marks) 22T3 Q2: Practical (10 marks) 22T3 Q3: Practical (10 marks) 22T3 Q4: Theory (10 marks) 22T3 Q5: Theory (10 marks) 22T3 Q6: Practical (10 marks) 22T3 Q7: Theory (10 marks) 22T3 Q8: Theory (10 marks)
Preparation
Before attempting the weekly exercises you should re-read the relevant lecture slides and their accompanying examples.
Getting Started
Create a new directory for this week’s exercises called lab10, change to this directory, and fetch the provided code for this week by running these commands:
$ mkdir lab10
$ cd lab10
$ 6991 fetch lab 10

Or, if you’re not working on CSE, you can download the provided code as a tar file.
(OPTIONAL) XRCIS:
Exam Preamble
Exam Condition Summary
This exam is “Open Book”
Joint work is NOT permitted in this exam
You are NOT permitted to communicate (email, phone, message, talk) with anyone during this exam, except for the COMP6991 staff via
The exam paper is confidential, sharing it during or after the exam is prohibited.
You are NOT permitted to submit code that is not your own
You may NOT ask for help from online sources.
Even after you finish the exam, on the day of the exam, do NOT communicate your exam answers to anyone. Some students have extended time to complete the exam.
Do NOT place your exam work in any location, including file sharing services such as Dropbox or GitHub, accessible to any other person.
Your zpass should NOT be disclosed to any other person. If you have disclosed your zpass, you should change it immediately. The use of AI assistants is strictly prohibited in this exam. This includes services such as Github Copilot and OpenAI ChatGPT.
As a remark, I have personally pre-emptively fed the entire exam through ChatGPT. It has a very distinct linguistic flavour to its responses, and often incredibly confidently gives an entirely nonsensical answer. Please don’t mistakenly believe you won’t be caught if you opt to violate these conditions.
Deliberate violation of these exam conditions will be referred to Student Integrity Unit as serious misconduct, which may result in penalties up to and including a mark of 0 in COMP6991 and exclusion from UNSW.
You are allowed to use any resources from the course during the exam.
You are allowed to use small amounts of code (< 10 lines) of general-purpose code (not specific to the exam) obtained from a site such as Stack Overflow or other publicly available resources. You should attribute the source of this code clearly in an accompanying comment. Exam submissions will be checked, both automatically and manually, for any occurrences of plagiarism. By starting this exam, as a student of The University of New South Wales, you do solemnly and sincerely declare that you have not seen any part of this specific examination paper for the above course prior to attempting this exam, nor have any details of the exam's contents been communicated to you. In addition, you will not disclose to any University student any information contained in the abovementioned exam for a period of 24 hrs after the exam. Violation of this agreement is considered Academic Misconduct and penalties may apply. For more information, read the UNSW Student Code, or contact the Course Account. This exam comes with starter files. You will be able to commence the exam and fetch the files once the exam commences. You may complete the exam questions using any platform you wish (VLab, VSCode, etc). You should ensure that the platform works correctly. You may submit your answers, using the give command provided below each question. You can use give to submit as many times as you wish. Only the last submission will be marked. Do NOT leave it to the deadline to submit your answers. Submit each question when you finish working on it. Please make sure that you submit all your answers at the conclusion of the exam - running the autotests does not automatically submit your code. Autotests are available for all practical questions to assist in your testing. You can use the command: 6991 autotest Passing autotests does not guarantee any marks. Remember to do your own testing! No marks are awarded for commenting - but you can leave comments for the marker to make your code more legible as needed Language Restriction All programming questions must be answered entirely in Rust. You may not use any other programming languages. You are not permitted to use third-party crates other than the standard library (std). Fit to Sit By sitting or submitting an assessment on the scheduled assessment date, a student is declaring that they are fit to do so and cannot later apply for Special Consideration. If, during an exam a student feels unwell to the point that they cannot continue with the exam, they should take the following steps: 1. Stopworkingontheexamandtakenoteofthetime 3. ImmediatelysubmitaSpecialConsiderationapplicationsayingthatyoufeltillduringtheexamandwereunabletocontinue 4. Ifyouwereabletoadviseusoftheillnessduringtheassessment(asabove),attachscreenshotsofthisconversationtothe Special Consideration application Technical Issues If you experience a technical issue, you should take the following steps: 1. IfyourissueiswiththeconnectiontoCSE,pleasefollowthefollowingsteps: If you are using VLab: Try exiting VLAB and reconnecting again - this may put you on a different server, which may improve your connection. If you are still experiencing problems, you can try changing how you connect to the CSE servers. Consider: By using VSCode (with SSH-FS extension): https://www.cse.unsw.edu.au/~learn/homecomputing/vscode/ By using SSH: https://taggi.cse.unsw.edu.au/FAQ/Logging_In_With_SSH/ If you are using VSCode remote-ssh: Try disconnecting VSCode, and then changing the URL from vscode.unsw.edu.au to vscode2.unsw.edu.au. If you are using SSH: Try disconnecting SSH and reconnecting again. 2. IfthingsarestillNOTworking,takescreenshotsofasmanyofthefollowingaspossible: error messages screen not loading timestamped speed tests power outage maps 4. ASpecialConsiderationapplicationshouldbesubmittedimmediatelyaftertheconclusionoftheassessment,alongwiththe appropriate screenshots. (OPTIONAL) XRCIS: Question 1 Q1.1 (2 marks) A C programmer who is starting to learn Rust has asked: "Aren't match statements just complicated if statements?". Give a specific example of a situation where you believe a match statement would significantly improve code quality, instead of a series of if/else statements. Q1.2 (2 marks) The following Rust code fails to compile, but equivalent code in other popular programming languages (e.g. C, Java, Python) compiles and/or works correctly. Explain what issue(s) prevent the Rust compiler from building this code, and the philosophy behind this language decision. Q1.3 (3 marks) In other languages, the operation: "first_string" + "second_string" produces a new string, "first_stringsecond_string". This particular operation does not work in Rust. 1. Why does Rust not implement this operation on the &str type? 2. WoulditbepossiblefortheRustlanguagedeveloperstoimplementthis?Whatrustfeaturewouldtheyusetoimplementit? 3. DoyouthinktheRustlanguagedevelopersshouldimplementthisoperation?Giveonereasontojustifyyouranswer. Q1.4 (3 marks) Rust beginners have posted some questions on a programming forum: 1. HowcanIturnanownedvalueintoasharedborrow? 2. HowcanIturnasharedborrowintoanexclusiveborrow! 3. WhyamIallowedtoturnanexclusiveborrowintoasharedborrow? Provide a short answer to each question. Importantly, note that some questions might ask for something that is not possible (in which case, you should say so and explain why). (OPTIONAL) XRCIS: In this activity, you will be building a small text searching system. It should search a large string for sentences that contain a particular search term. Another function will then look through all the search results to determine how often each sentence was found. You have been given starter code which does not yet compile. Your task is to fill in both todo!() statements, as well as to add lifetimes where required in order to build your code. You are not permitted to change the return type of functions, the names of structs, or the types of structs. You may also not change the main function, and you should expect that the main function could be changed during testing. You will, however, have to add lifetimes to existing types in order to successfully compile your code. This is an example of the expected behaviour: struct Coordinate { y: i32, }; let coord1 = Coordinate {x: 1, y: 2}; let coord2 = coord1; let coord_sum = Coordinate { x: coord1.x + coord2.x, y: coord1.y + coord2.y }; (OPTIONAL) XRCIS: In this question, your task is to complete two functions, and make them generic: zip_tuple and unzip_tuple. Right now, the zip_tuple function takes a Vec and returns a tuple: (Vec, Vec). The unzip_tuple function performs the inverse of this.
This code currently does not compile, because q3_lib (i.e. lib.rs) does not know what the type of Coordinate is. Rather than telling the functions what type Coordinate is, in this exercise we will make the functions generic, such that it works for both q3_a (i.e. main_1.rs) and q3_b (i.e. main_2.rs). This is to say, tuple_unzip should work for any Vec such that T implements Into into a 2- tuple of any 2 types, and tuple_zip should work for any Vec<(T, U)> such that (T, U) implements Into into any type.
Once you have modified your function signatures for tuple_unzip and tuple_zip, you should find that the only concrete type appearing within the signature is Vec. In other words, the functions should work for any type which can be created from a 2-tuple and which can be converted into a 2-tuple.
(OPTIONAL) XRCIS:
$ 6991 cargo run test_data/test_data.txt
Finished dev [unoptimized + debuginfo] target(s) in 0.36s Running `target/debug/prac_q2`
the universe
Found 1 results for ‘there’.
Found 9 results for ‘very’.
Found 1 results for ‘prove’.
Found 11 results for ‘the universe’.
‘8 billion years ago, space expanded very quickly (thus the name “Big Bang”)’ occured 1 times.
‘According to the theory the universe began as a very hot, small, and dense superforce (the mix of the four
fundamental forces), with no stars, atoms, form, or structure (called a “singularity”)’ occured 2 times.
‘Amounts of very light elements, such as hydrogen, helium, and lithium seem to agree with the theory of the Big
Bang’ occured 1 times.
‘As a whole, the universe is growing and the temperature is falling as time passes’ occured 1 times.
‘Because most things become colder as they expand, scientists assume that the universe was very small and very
hot when it started’ occured 2 times.
‘By measuring the redshift, scientists proved that the universe is expanding, and they can work out how fast
the object is moving away from the Earth’ occured 2 times.
‘Cosmology is the study of how the universe began and its development’ occured 1 times.
‘Other observations that support the Big Bang theory are the amounts of chemical elements in the universe’
occured 1 times.
‘The Big Bang is a scientific theory about how the universe started, and then made the stars and galaxies we
see today’ occured 1 times.
‘The Big Bang is the name that scientists use for the most common theory of the universe, from the very early
stages to the present day’ occured 2 times.
‘The more redshift there is, the faster the object is moving away’ occured 1 times.
‘The most commonly considered alternatives are called the Steady State theory and Plasma cosmology, according
to both of which the universe has no beginning or end’ occured 1 times.
‘The most important is the redshift of very far away galaxies’ occured 1 times.
‘These electromagnetic waves are everywhere in the universe’ occured 2 times.
‘This radiation is now very weak and cold, but is thought to have been very strong and very hot a long time
ago’ occured 1 times.
‘With very exact observation and measurements, scientists believe that the universe was a singularity
approximately 13’ occured 2 times.

Q4.1 (2 marks)
Steve is writing some Rust code for a generic data structure, and creates a (simplified) overall design alike the following:
He soon finds that this design is not sufficient to model his data structure, and revises the design as such:
Give an example of a data-structure that Steve could be trying to implement, such that his first design would not be sufficient, and instead his second design would be required for a correct implementation. Furthermore, explain why this is the case.
Q4.2 (3 marks)
Emily is designing a function that has different possibilities for the value it may return. She is currently deciding what kind of type she should use to represent this property of her function.
She has narrowed down three possible options:
2. Atraitobject
3. A generic type (as fn foo(…) -> impl Trait)
For each of her possible options, explain one possible advantage and one possible disadvantage of that particular choice.
Q4.3 (5 marks)
Rust’s macro system offers an extremely flexible method for code generation and transfiguring syntax, but this language feature comes with certain costs. Identify 3 downsides to the inclusion, design, or implementation of Rust’s macro system.
(Note that your downsides may span any amount and combination of the categories above. e.g. you could write all 3 on just one category, or one on each, or anything in-between.)
(OPTIONAL) XRCIS:
Q5.1 (3 marks)
In many other popular programming languages, mutexes provide lock() and unlock() methods which generally do not return any value (i.e. void).
What issues could this cause?
How does Rust differently implement the interface of a Mutex, and what potential problems does that help solve?
Q5.2 (2 marks)
struct S {
// some fields…
fn my_func(value: T) {
struct S {
// some fields…
impl S {
fn my_func(value: T) {

In Rust, locking a Mutex returns a Result, instead of simply a MutexGuard. Explain what utility this provides, and why a programmer might find this important.
Q5.3 (3 marks)
While reviewing someone’s code, you find the following type: Box i32 + Send>.
Explain what the + Send means in the code above?
Explain one reason you might need to mark a type as Send, and what restrictions apply when writing a closure that must be Send.
Q5.4 (2 marks)
Your friend tells you they don’t need the standard library’s channels, since they’ve implemented their own alternative with the following code:
use std::collections::VecDeque;
use std::sync::Mutex;
use std::sync::Arc;
use std::thread;
#[derive(Clone, Debug)]
struct MyChannel {
internals: Arc>>
impl MyChannel {
fn new() -> MyChannel {
MyChannel {
internals: Arc::new(Mutex::new(VecDeque::new()))
fn send(&mut self, value: T) {
let mut internals = self.internals.lock().unwrap(); internals.push_front(value);
fn try_recv(&mut self) -> Option {
let mut internals = self.internals.lock().unwrap(); internals.pop_back()
fn main() {
let mut sender = MyChannel::::new();
let mut receiver = sender.clone();
sender.send(5);
thread::spawn(move || {
println!(“{:?}”, receiver.try_recv())
}).join().unwrap();
Identify a use-case where this implementation would not be sufficient, but the standard library’s channel would be. Furthermore, explain why this is the case.
(OPTIONAL) XRCIS:
The “Read Copy Update” pattern is a common way of working with data when many sources need to be able to access data, but also to update it. It allows a user to access a value whenever it’s needed, achieving this by never guaranteeing that the data is always the latest copy. In other words, there will always be something, but it might be slightly old. In some cases, this trade-off is one that’s worth making.

Programming Help
In this task, you will be implementing a small RCU data-structure. You should ensure that:
Multiple threads are able to access a given piece of data.
Threads can pass a closure to the type which updates the data.
When created, the RCU type starts at generation 0. Every time it is updated, that counter is increased by one.
You have been given some starter code for the type RcuType, including some suggested fields, and the required interface. Ensure you first understand the requirements of this task, and then implement the methods described in the starter code.
(OPTIONAL) XRCIS:
Q7.1 (5 marks)
Gavin writes a blog post critical of Rust, especially with respect to unsafe. In his blog post, he claims that it’s not possible to have any confidence in the overall safety of a Rust program since “even if you only write safe Rust, most standard functions you call will have unsafe code inside them”.
1. StatetowhatextentyouagreewithGavin’sclaim.
2. Giveatleastthreeargumentsthatsupportyourconclusion.
Q7.2 (5 marks)
Hannah writes a Rust program that intends to call some C code directly through FFI. Her C function has the following prototype:
int array_sum(int *array, int array_size); and the following implementation:
Note that you can assume that this C code is written entirely correctly, and the below extern “C” block is an accurate translation of the C interface.
Her Rust code is currently written as follows:
int array_sum(int *array, int array_size) {
int sum = 0;
for (int i = 0; i < array_size; i++) { sum += array[i]; } return sum; } Code Help, Add WeChat: cstutorcs She expects that if she runs her code, it should print that the C code summed to 69910. To her surprise, she runs the program and finds the following: Hannah correctly concludes that there must be a problem with her Rust code. 1. Identifytheissuethatiscausingtheprogramtomisbehave. 2. DescribeapracticalsolutionHannahcouldusetofixthebug. 3. ExplainwhyRustwasn'tabletocatchthisissueatcompile-time. (OPTIONAL) XRCIS: The final question of the exam will be a more open-ended question which will ask you to perform some analysis or make an argument. Your argument will be judged alike an essay (are your claims substantiated by compelling arguments). Remember that you will not get any marks for blindly supporting Rust. A friend of yours has just read this article, and thinks that it means they shouldn't learn Rust. Read through the article, and discuss the following prompt: Rust is not worth learning, as explained by this article. The overall structure of your answer is not marked. For example, your answer may include small paragraphs of prose accompanied by dot-points, or could instead be posed as a verbal discussion with your friend. Regardless of the structure / formatting you choose, the substance of what you write is the most important factor, and is what will determine your overall mark for this question. From UNSW's Glossary of Task Words: $ 6991 cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.00s Running `target/debug/ffi` Calling C function with array of size: 10 C says the sum was: -2039199222 use std::ffi::c_int; #[link(name = "c_array")] extern "C" { fn array_sum(array: *mut c_int, array_size: c_int) -> c_int;
fn test_data() -> (*mut c_int, c_int) {
let size = 10;
let array = vec![6991; size].as_mut_ptr();
(array, size as c_int)
fn main() {
let sum = {
let (array, size) = test_data();
// Debug print:
let message = format!(“Calling C function with array of size: {size}”);
println!(“{message}”);
unsafe { array_sum(array, size) }
println!(“C says the sum was: {sum}”);

Code Help
Discuss Investigate or examine by argument. Examine key points and possible interpretations, sift and debate, giving reasons for and against. Draw a conclusion.
(OPTIONAL) XRCIS:
22T3 Q1: Theory (10 marks)
Q1.1 (3 marks)
1. Explain the difference between the Option and Result types. (1 mark) 2. Giveanexampleofwhereeachmightbeused.(2marks)
Write your answer in exam_q1/q1_1.txt.
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q1_1 q1_1.txt
Q1.2 (2 marks)
The following Rust code fails to compile, but equivalent code in other popular programming languages (e.g. C, Java, Python) compiles and/or works correctly.
1. Explainwhatissue(s)preventtheRustcompilerfrombuildingthiscode(1mark). 2. Explainthephilosophybehindthislanguagedecision(1mark).
Write your answer in exam_q1/q1_2.txt.
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q1_2 q1_2.txt
Q1.3 (2 marks)
Your friend has asked you to teach them Rust. They think a great place to begin would be your teaching them to write their own implementation of a doubly-linked list (i.e. a list in which each node is stored on the heap, with references to the previous node and the next node).
Give two reasons to explain why this is not a problem well-suited for Rust. (1 mark per reason)
Write your answer in exam_q1/q1_3.txt.
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q1_3 q1_3.txt
let i: u32 = 32;
let j: i32 = -1;
println!(“{}”, i + j);

Q1.4 (3 marks)
A COMP6991 student has decided to build their own operating system in Rust. When implementing the ability to open and read from files, they design these functions based on how Linux deals with files.
/// This function takes a path to a file; and a mutable reference to a `usize`.
/// If the file at `file_path` can be opened, the function will write a unique
/// `file_id` to the given mutable reference, and return 0. If the file cannot
/// be opened, the function will return an error code.
fn open_file(file_path: &str, file_id: &mut usize) -> usize;
/// This`function takes a `file_id` the user has already obtained, as well as a
/// `buffer` to write bytes to, and a `max_read_size`. The function tries to
/// copy `max_read_size` bytes into `buffer`. It returns the actual number of
/// bytes read. If there is an error, it returns a negative error code.
fn read_file(file_id: i32, buffer: &[u8], max_read_size: usize) -> i32;
Identify three issues in this students plan (either with their design, or their ability to implement their plan in Rust), and three accompanying Rust features that could be used to fix them. (1 mark per issue+fix)
Write your answer in exam_q1/q1_4.txt.
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q1_4 q1_4.txt
(OPTIONAL) XRCIS:
22T3 Q2: Practical (10 marks)
In this activity, you will be finding the differences between two rolls of people. A COMP6991 tutor has collected two rolls of people, and wants to know who’s unique to the first one; who’s unique to the second one; and who is on both lists.
You will be given two string references, called left and right. On each line is the name of a person. For every person on the left roll, you should return either DiffResult::LeftOnly or DiffResult::Both containing a string reference to that line, depending on whether they’re in the right list also. For every person on the right roll, you should return DiffResult::RightOnly containing a reference to that line if they are not in the left roll. You can assume that the people on any single roll are unique. That is, you won’t see two of the same person on the left roll, nor two of the same person on the right roll.
Before returning, you should sort your list of differences alphabetically by their names. Note that since DiffResult derives PartialOrd + Ord, you should simply be able to call .sort() on your final Vec.
You have been given starter code which does not yet compile. Your task is to fill in the todo!() statement, as well as to modify the lifetimes where required in order to build your code.
You are not permitted to change the return type of functions, the names of structs, or the types of structs. You may also not change the main function, and you should expect that the main function will be changed during testing. Specifically, the main function could be changed to extract DiffResult::RightOnly or DiffResult::Both. You will, however, have to add or modify lifetimes to existing types in order to successfully compile your code.
This is an example of the expected behaviour:

Write your answer in exam_q2/src/lib.rs.
When you think your program is working, you can use autotest to run some simple automated tests:
$ 6991 autotest
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q2 lib.rs
(OPTIONAL) XRCIS:
22T3 Q3: Practical (10 marks)
In this task, you will build a data-structure, called a “DBMap”. This type will wrap a Vec of tuples, of the form (key, value). Currently, the type only works for tuples of the form (i32, &’static str), however you will need to modify this so it works for any tuples where the key is Eq. Your task is to make this struct generic over all valid types for both its keys and values, then to implement a method on this data-structure.
The method you will implement is called merge. It should take ownership of two DBMaps with the same type of key, and then return a new DBMap with its values being tuples. To describe the algorithm merge uses, we will call one of the DBMaps self, and one of them other.
To create the new DBMap, you should iterate over each element in self. We will call these key and value You should then try to find the first element in other with an equal key. We will call that other_value. You should insert (key, (value, Some(other_value))) into the new DBMap. If you cannot find a matching value in other, you should insert (key, (value, None)) into the new DBMap.
Your implementation should be generic, such that the key is any type which supports equality checking; and the value is any type.
Your implementation should compile with both the main functions provided, however you should assume that more main functions may be tested during marking.
You may assume that any one individual DBMap will be comprised of totally unique keys. An example of a merge is shown below:
$ 6991 cargo run test_data/test_data.txt
Finished dev [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/prac_q2`
Left Only: Barry
Left Only: Netanya
Left Only: Toby
Left Only: Zac

Stock Prices Key
Apples Pears
For example,
Stock Quantity
Value Key Value
3.5 Pears 50 4.5 Apples 100
200 Peaches 200
Merge of Stock Prices and Quantity
Key Apples Pears Caviar
(3.5, Some(100)) (4.5, Some(50)) (200, None)
$ 6991 cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/exam_q3`
#1: Max Verstappen (Red Bull Racing)
#3: Daniel Riccardo (None)
#4: Lando Norris (McLaren)
#5: Sebastian Vettel (None)
#6: Nicholas Latifi (None)
#7: Kimi Räikkönen (None)
#9: Nikita Mazepin (None)
#11: Sergio Pérez (Red Bull Racing)
Write your answer in exam_q3/src/lib.rs.
When you think your program is working, you can use autotest to run some simple automated tests:
$ 6991 autotest
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q3 lib.rs
(OPTIONAL) XRCIS:
22T3 Q4: Theory (10 marks)
Q4.1 (2 marks)
Therese is writing a library to help sell her car. The library defines a Car trait as follows:
trait Car {
fn get_price(&self) -> u32;
Users of the library will create their own structs which represent specific cars by implementing the Car trait. As seen in the trait definition, all Cars have a price.
Therese wants to write a function to total the cost of all the cars in a slice. As she wants this to work for any models of Car, she considers two potential approaches:
fn get_total_price(cars: &[C]) -> u32; and
fn get_total_price(cars: &[Box]) -> u32; Question:
1. Explainthedifferencebetweenthetwoapproaches.(1mark)

2. GiveonereasonwhyTheresemightchooseeachapproach.(1mark)
Write your answer in exam_q4/q4_1.txt.
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q4_1 q4_1.txt
Q4.2 (2 marks)
Daniel is trying to design a function that counts the number of whitespace characters in some text. He starts with the first design…
… and submits this for code review. Another software engineer on his team suggests the following change…
… which Daniel accepts and resubmits. Finally, a senior engineer suggests a further change:
1. WhyisthefirstsuggestedchangeanimprovementonDaniel’soriginaldesign?(1mark) 2. Whyisthesecondsuggestedchangeanimprovementontheseconddesign?(1mark)
Write your answer in exam_q4/q4_2.txt.
When you are finished working on your answer, submit your work with give:
$ give cs6991 exam_q4_2 q4_2.txt
Q4.3 (3 marks)
Olivia is working on a roll-call system to help take attendance at a class she teaches. She writes t