Week 10 Laboratory Exercises

Objectives

  • Show how the final exam works.

Activities To Be Completed

The following is a list of all the activities available to complete this week...

  • Exam Prelude and Q1
  • Q2
  • Q3
  • Q4
  • Q5
  • Q6
  • Q7
  • Q8

Preparation

Before the lab you should re-read the relevant lecture slides and their accompanying examples.

Getting Started

Create a new directory for this lab 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.

Exercise:
Exam Prelude and Q1

December 2022

Time for the exam: 3 hours

This exam contains 8 questions, each of equal weight.

Total number of marks: 80

You should answer all questions.

The practice exam will not be marked.

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 cs6991.exam@cse.unsw.edu.au
  • 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.
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 (where X is the question number): give cs6991 exam_qX exam_qX.c
  • 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 (where X is the question number): 6991 autotest prac_qX
  • Passing autotests does not guarantee any marks. Remember to do your own testing!
  • One mark will be deducted from practical questions where they do not pass rustfmt.
  • 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 other programming languages.
  • You are not permitted to use crates other than the standard libraries.

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. Stop working on the exam and take note of the time
  2. Contact us immediately, using cs6991.exam@cse.unsw.edu.au, and advise us that you are unwell
  3. Immediately submit a Special Consideration application saying that you felt ill during the exam and were unable to continue
  4. If you were able to advise us of the illness during the assessment (as above), attach screenshots of this conversation to the Special Consideration application

Technical Issues

If you experience a technical issue, you should take the following steps:

  1. If your issue is with the connection to CSE, please follow the following steps:
    • 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:
    • 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. If things are still NOT working, take screenshots of as many of the following as possible:
    • error messages
    • screen not loading
    • timestamped speed tests
    • power outage maps
  3. Contact should be made immediately to advise us of the issue at cs6991.exam@cse.unsw.edu.au
  4. A Special Consideration application should be submitted immediately after the conclusion of the assessment, along with the appropriate screenshots.

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.

struct Coordinate {
    x: i32,
    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 };

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. Would it be possible for the Rust language developers to implement this? What rust feature would they use to implement it?
  3. Do you think the Rust language developers should implement this operation? Give one reason to justify your answer.

Q1.4 (3 marks)

Rust beginners have posted some questions on a programming forum:

  1. How can I turn an owned value into a shared borrow?
  2. How can I turn a shared borrow into an exclusive borrow!
  3. Why am I allowed to turn an exclusive borrow into a shared borrow?

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).

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q2

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:

 6991 cargo run test_data/test_data.txt 
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s
    Running `target/debug/prac_q2`
there
very
prove
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.

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q3

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<Coordinate> and returns a tuple: (Vec<i32>, Vec<i32>). 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<T> 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.

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q4

Q4.1 (2 marks)

Steve is writing some Rust code for a generic data structure, and creates a (simplified) overall design alike the following:

struct S {
    // some fields...
}

impl S {
    fn my_func<T>(value: T) {
        todo!()
    }
}

He soon finds that this design is not sufficient to model his data structure, and revises the design as such:

struct S<T> {
    // some fields...
}

impl<T> S<T> {
    fn my_func(value: T) {
        todo!()
    }
}

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:

  1. An enum
  2. A trait object
  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.)

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q5

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)

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<dyn Fn() -> 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<T> {
    internals: Arc<Mutex<VecDeque<T>>>
}

impl<T> MyChannel<T> {
    fn new() -> MyChannel<T> {
        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<T> {
        let mut internals = self.internals.lock().unwrap();
        internals.pop_back()
    }
}

fn main() {
    let mut sender = MyChannel::<i32>::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.

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q6

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.

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<T>, 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.

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q7

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. State to what extent you agree with Gavin's claim.
  2. Give at least three arguments that support your conclusion.

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:
int array_sum(int *array, int array_size) {
	int sum = 0;
	for (int i = 0; i < array_size; i++) { sum += array[i]; }
	return sum;
}
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:

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}");
}

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:

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

Hannah correctly concludes that there must be a problem with her Rust code.

  1. Identify the issue that is causing the program to misbehave.
  2. Describe a practical solution Hannah could use to fix the bug.
  3. Explain why Rust wasn't able to catch this issue at compile-time.

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Exercise:
Q8

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.

When you are finished working on this exercise, you must submit your work by running give:

6991 give

You must run give before 2022-12-12 21:00:00 to obtain the marks for this exercise. Note that this is an individual exercise; the work you submit with give must be entirely your own.

Submission

When you are finished each exercise make sure you submit your work by running give.

You can run give multiple times. Only your last submission will be marked.

Don't submit any exercises you haven't attempted.

If you are working at home, you may find it more convenient to upload your work via give's web interface.

Remember you have until 2022-12-12 21:00:00 to submit your work.

You cannot obtain marks by e-mailing your code to tutors or lecturers.

Automarking will be run several days after the submission deadline, using test cases different to those autotest runs for you. (Hint: do your own testing as well as running autotest.)

After automarking is run you can view your results here.

Lab Marks

When all components of a lab are automarked you should be able to view the the marks via give's web interface or by running this command on a CSE machine:

6991 classrun -sturec