ECE326 – Fall 2019: Week 3 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. Overloading virtual functions in ++ is an example of multiple dispatch. T F Function overloading in C++ is done statically (static dispatch), at compile time.

2. You can declare an opaque on the stack. T F No. You must know the size of a data type to be able to declare it on the stack, but an is not defined, making it impossible to calculate its size.

3. Pure virtual functions are not necessarily pure functions. T F

Pure virtual functions can still have side effects such as modifying global variables, which makes it not always a pure function.

4. A overloading an operator is an example of dynamic dispatch. T F

Yes, for example, virtual int operator+(int val) const; 5. Dynamically-typed interpreted language cannot implement early binding. T F Only compiled languages can legitimately implement early binding (name to address translation)

2. Short Answers

1. Override the eat method in Animal so that the eat method in Dog will, in addition to what Animal.eat already does, print “Wags its tail” at the very end. Show the entire class definition for Dog. [3 marks]

class Animal: … # may change this function in the future def eat(self, food): # a mistake was fixed (self added) print(str(food) + “ is delicious”)

class Dog(Animal): def eat(self, food): super().eat(food) # or Animal.eat(self, food) print("Wags its tail")

2. Write an expression with equivalent result as the following list comprehension, using only the map and filter function for control flow. [2 marks]

[ str(v) for v in range(10, 100) if not (v//10+v%10)%7 ]

def cond(v): return not (v//10+v%10)%7

b = list(map(str, filter(cond, range(10, 100))))

3. Prototype-based Programming [10 marks]

In Prototype-based programming, all objects have the type Object. The base object initially has no attribute. We wish to program with this paradigm in Python. Create a Person object out of the base object, followed by inheriting from the Person object to create a Student object. Finally, make an instance of Student. A Person object should have the data attributes: name, age, and gender, with a method called birthday() that increments age. A Student object should have the data attributes: id, gpa, and year. Create an instance of Student named “me” with your credential (can be fake). Choose suitable defaults for the prototypes. class Object: pass base = Object()

import copy student.id = 0 person = copy.deepycopy(base) student.gpa = 0 person.name = “” student.year = 1900 person.age = 26 me = copy.deepcopy(student) person.gender = “unknown” me.name = “jack” def bday(self): me.gender = “male” self.age += 1 me.id = 123456789 Object.birthday = bday me.gpa = 3 student = me.year = 2015 copy.deepycopy(person)

4. Virtual Tables [10 marks] a. For the following inheritance hierarchy, draw a virtual table for each class and draw an arrow from each entry in the virtual table to their definition in the C++ classes. [7 marks]

A::vtable struct A { virtual void foo() { cout << “A.foo”; } A::foo virtual void bar() { cout << “A.bar”; } void baz() { cout << “A.baz”; } A::bar };

B::vtable struct B : public A { A::foo virtual void bar() { cout << “B.bar”; } B::bar };

C::vtable struct C : public B { C::foo virtual void foo() { cout << “C.foo”; } B::bar void baz() { cout << “C.baz”; } };

D::vtable struct : public A { D::foo virtual void foo() { cout << “D.foo”; } A::bar void baz() { cout << “D.baz”; } };

b. What is the output of the following program? [3 marks]

D d = D(); C c = C(); A * ad = &d; A * ac = &c; ac->baz(); ad->foo(); ac->bar();

A.baz D.foo B.bar

ECE326 – Fall 2019: Week 4 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. With C3 Linearization, Python completely solves the diamond problem. T F

2. 0x8888FEDC is a 4- aligned address. T F

3. Suppose class A is inherited by class B, and C, monotonicity guarantees that A will behave the same for both B and C. T F

4. Adding a new pure virtual function to a base class with many existing derived classes is an example of a fragile base class problem. T F

5. The main difference between delegation and type embedding is that with type embedding, you can no longer reference the embedded member by name. T F

2. Multiple Answers [2 marks each]

Pick all answer(s) that are correct. You will lose 1 mark per wrong choice, down to 0 marks. 1. Which of the following are true about mixins?

(a) It requires subclass to complete its implementation. Not Necessarily. (b) It can contain both member variables and functions. (c) It is used as a super type to the derived class. (d) Using it requires method forwarding. Only composition requires forwarding. (e) The order in which mixins are composed may change behaviour of the subclass.

2. Java only supports single inheritance with runtime polymorphism. Which of the following is true?

(a) Java does not support mixins. Mixin requires multiple inheritance. (b) Java does not need virtual tables. Still required to implement dynamic dispatch. (c) Casting pointers (internally, Java does not expose pointers to programmers) in Java will never require point offsetting. (d) Java does not need to deal with inheritance-related ambiguity. (e) Java does not have method resolution order. Only late binding languages require MRO. 3. Virtual Base Class in C++ [10 marks]

Draw the data layout of class X (include padding assuming 8-byte alignment, and write down the size of each sub-structure) and all the virtual tables generated for class X and its ancestors. struct B { int b1; int b2; virtual void foo() { cout << “A.foo”; } virtual ~A() {} }; struct P : virtual public B { long p1; virtual void foo() override { cout << “P.foo”; } }; struct Q : public P { int q1; }; struct N : virtual public B { char n1[30]; }; struct X : public N, public Q { int x1; virtual void foo() override { cout << “X.foo”; } };

struct X B::b2 : int B::b1 : int 16 B::__vptr

X::x1 : int 4 bytes Q::q1 : int 4 bytes P::p1 : long 16 bytes P::__vptr

padding: 2 bytes 40 bytes N::n1 : char[30] N::__vptr X::N::vtable virtual base offset: 64 offset to “bottom”: 0 typeinfo = typeinfo(X) X::foo X::~X()

X::B::vtable X::P::vtable virtual base offset: 0 virtual base offset: 24 offset to “bottom”: 64 offset to “bottom”: 40 typeinfo = typeinfo(X) typeinfo = typeinfo(X) X::foo X::foo X::~X() X::~X() 4. Method Resolution Order [10 marks]

a. For the following inheritance hierarchy in Python, draw a diagram of the hierarchy. [2 marks]

class A: pass class B: pass class C: pass class D: pass class E: pass class P(A, B, C): pass class Q(D, B, E): pass class R(D, A): pass class X(P, R, Q): pass

b. What is the C3 Linearization of X? [8 marks]

L[A] = (A, o) L[B] = (B, o) L[C] = (C, o) L[D] = (D, o) L[E] = (E, o) L[P] = (P, A, B, C, o) L[Q] = (Q, D, B, E, o) L[R] = (R, D, A, o) L[X] = (X, merge((P, A, B, C, o), (R, D, A, o), (Q, D, B, E, o), (P, R, Q))) = (X, P, merge((A, B, C, o), (R, D, A, o), (Q, D, B, E, o), (R, Q))) = (X, P, R, merge((A, B, C, o), (D, A, o), (Q, D, B, E, o), (Q))) = (X, P, R, Q, merge((A, B, C, o), (D, A, o), (D, B, E, o))) # A bad head, in tail of 2nd list = (X, P, R, Q, D, merge((A, B, C, o), (A, o), (B, E, o))) = (X, P, R, Q, D, A, merge((B, C, o), (o), (B, E, o))) = (X, P, R, Q, D, A, B, merge((C, o), (o), (E, o))) = (X, P, R, Q, D, A, B, C, E, o)

ECE326 – Fall 2019: Week 5 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. is a subset of metaprogramming. T F

Neither is a subset of each other, but they do have overlaps.

2. If no deep copy is required (e.g. class has no pointer), move semantics performs no better than copy semantics. T F

3. If specialization is not used (i.e. not instantiated), its code is not generated for the final executable. T F

4. For template T foo(), you can write int a = foo() to instantiate the function template foo with an int parameter . T F

Have to write foo() because C++ does not do type inference based on return type.

5. The new operator in C++ couples heap allocation and constructor invocation. T F 2. Short Answers

1. Use container_of to return a pointer to the parent object of member base. [2 marks]

struct base { int x, y, z; };

struct derived { int a; struct base b; char c[10]; };

struct derived * get_derived(struct base * ptr) {

return container_of(ptr, struct derived, b);

} 2. Implement binary search algorithm using a function template, assume the array is sorted and return -1 upon not found. [5 marks] template /* find index of val in array of size n */ int binary_search(const T & val, T * array, int n) {

int top = n-1; int bot = 0;

while (bot <= top) { int mid = (top + bot)/2;

if (array[mid] == val) return mid; else if (array[mid] < val) bot = mid+1; else top = mid-1; }

return -1;

}

3. Implement a template class named Triple that is a tuple of 3 elements of the same type. Overload enough operators so that binary search template you implemented above can be instantiated for Triple. Use lexicographical order. [8 marks] template struct Triple { T a, b, c;

Triple() : a(0), b(0), c(0) {}

Triple(T && a, T && b, T && c) : a(std::move(a)) , b(std::move(b)) , c(std::move(c)) {}

bool operator==(const Triple & rhs) { return a == rhs.a && b == rhs.b && c == rhs.c; }

bool operator<(const Triple & rhs) { if ( a < rhs.a ) return true; else if ( a > rhs.a ) return false; else if ( b < rhs.b ) return true; else if ( b > rhs.b ) return false; else if ( c < rhs.c ) return true; /* c >= rhs.c */ return false; } };

3. Generic Programming [10 marks]

Create a generic Queue class without using templates. Implement the Queue using a singly linked list, with the member functions, push_back, that pushes new elements to end of the queue, front, which returns the first element of the queue, and pop_front, which removes the first element of the queue. class Queue { struct Node { Node * next; void * data;

Node(void * data, Node * next=nullptr) : next(next) , data(data) {} ~Node() { /* managed by Queue */ } } * head, * tail; void (* dest_f)(void *); public: Queue(void (* destroy)(void *)) : head(nullptr) , tail(nullptr) , dest_f(destroy) {}

~Queue() { Node * curr = head; while (curr != nullptr) { Node * temp = curr; curr = curr->next; dest_f(temp->data); delete temp; } }

void * front() { if (head == nullptr) { return nullptr; } return head->data; }

bool push_back(void * data) { Node * node = new Node(data);

if (node == nullptr) { return false; }

if (head == nullptr) { head = tail = node; } else { tail->next = node; tail = node; }

return true; }

bool pop_front() { Node * node;

if (head == nullptr) { return false; }

node = head; head = head->next; if (head == nullptr) { tail = nullptr; }

delete node; return true; } };

Note that you are not expected to write this entire class during a midterm. This was more for you to write some code.

4. Template Programming [10 marks]

Using the generic Queue made in Question 3, write a FIFO class template, which allows type- safe use of the generic Queue class for any parameterized type. Use move semantics for push_back instead of copy semantics.

template class Fifo : private Queue { static void destroy(void * ptr) { delete (T *)ptr; }

public: Fifo() : Queue(&Fifo::destroy) {}

bool push_back(T && elem) { return Queue::push_back(new T(std::move(elem))); }

T * front() { return (T *)Queue::front(); }

bool pop_front() { return Queue::pop_front(); } };

You would be expected to do something like this during the midterm, where the line of code you have to write is about 2 lines per 1 mark (assuming you write efficient code). You can write this same template class using composition instead of inheritance. Give that a try.

ECE326 – Fall 2019: Week 6 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. In Python, types are reified at runtime. T F

2. The decorator function is called every time the decorated function is called. T F Decorator is called once – after the decorated function is defined.

3. C++11 supports static reflection. T F

4. In multiple inheritance, TypeError is raised when there is a shared base . T F Sharing base is OK, as long as a single metaclass can be resolved unambiguously.

5. type is to classes as object is to instances. T F

2. Multiple Answers [2 marks each]

Pick all answer(s) that are correct. You will lose 1 mark per wrong choice, down to 0 marks. 1. Which of the following statements about descriptors or properties are true?

(a) A descriptor can manage multiple attributes at once, a property can only manage one. (b) A descriptor with only __get__ can be overwritten or deleted, a property with only getter cannot. (c) A descriptor can manage a method, a property cannot (data attribute only). (d) A descriptor keeps data within its own instance, a property uses that of the parent instance. (e) A descriptor with only __set__ has the same behaviour as a property with only setter.

(c) a property can return a method too. (d) a descriptor can still access an instance’s attributes, but usually you’d keep data within the descriptor. (e) a property with only setter is not readable. A descriptor with no __get__ will allow its attributes to be accessed 2. Which of the following statements about class decorators or are true?

(a) Both class decorators and metaclasses require only a callable object to work. (b) Both class decorators and metaclasses must return a class (new or existing). (c) Class decorators do not support inheritance, metaclasses do. (d) Class decorators modifies a class only after it is created, metaclasses modifies a class only before and during class creation. (e) Metaclass is the only way to overload operators for classes.

(b) class decorator only needs to return a callable that will create instances of the class. (c) Technically speaking, if the class decorator is a functor, then the functor supports inheritance. So both yes or no is accepted for this choice.

3. Decorator [10 marks]

Create a decorator, memoize, that will cache results of the decorated function. You may assume: 1. The decorated function will be a pure function. 2. Only positional arguments are used by the decorated function, no keyword arguments. 3. All arguments are hashable types

# Note that this will work for multiple functions because of # how closure works def memoize(func): cache = {} def memoizer(*args): if args in cache: return cache[args] else: result = func(*args) cache[args] = result return result return memoizer

4. Metaclass [10 marks]

Write a metaclass, MethodCounter, that will add the functionality to a class such that it counts how many times a method is called by any instance of the class. For example, if a called foo twice and b called foo once, then the count for foo should be three (both a and b are instances of the class that inherits your metaclass). Remember that it should keep a separate count for each method. Hint: use the built-in function callable to check if an attribute is callable.

def getattribute(self, name): # NOTE: cannot use super() here because # this function is defined outside of the # parent class val = object.__getattribute__(self, name) counter = object.__getattribute__(self, '_counter') if name in counter: counter[name] += 1 return val

class MethodCounter(type): def __new__(mcs, name, base, attrs): assert('_counter' not in attrs) counter = {} for a_name in attrs: if callable(attrs[a_name]): counter[a_name] = 0 attrs['_counter'] = counter attrs['__getattribute__'] = getattribute return super().__new__(mcs, name, base, attrs)

def get_count(cls, name): return cls._counter.get(name, 0)

5. Descriptor [10 marks]

Write a descriptor that will check the type and the range of the managed attribute before allowing it to be stored. The descriptor should also disallow deletion of the managed attribute. Here is how your descriptor is used:

class Foo: likelihood = Attr(type=float, minimum=0.0, maximum=1.0) Note that omitting any one of the checks results in not making that check. For example, if type is omitted, then type checking is disabled. Similarly, if maximum is omitted, then upper bound is unlimited (not checked). Raise AttributeError if the check fails.

class Attr: def __init__(self, type=None, minimum=None, maximum=None): self.type = type self.minimum = minimum self.maximum = maximum

def __get__(self, instance, owner): return getattr(self, '')

def __set__(self, instance, value): if self.type is not None and \ not isinstance(value, self.type): raise AttributeError("incorrect type") if self.minimum is not None and value < self.minimum: raise AttributeError("value less than minimum") if self.maximum is not None and value > self.maximum: raise AttributeError("value greater than maximum") self.value = value

def __delete__(self, instance): raise AttributeError("cannot delete this descriptor") ECE326 – Fall 2019: Week 7 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. A covariant tuple parameter is always type-safe. T F E.g. Tuple can always replace Tuple (tuples are immutable).

2. Widening conversion guarantees you can get back the original data if needed. T F Loss of precision can occur.

3. In C++, type inference for variable declaration (using the auto keyword) cannot fail. T F

4. systems do not have knowledge of the underlying . T F

5. explicit keyword is used to prevent implicit conversion of class objects when the class overloads the cast operator. T F It’s used to prevent implicit construction of an object that fits an argument and its constructor fits the input argument to a function, e.g. calling foo(1) for foo(Bar x) and Bar has a constructor Bar(int i).

2. Short Answers

1. Give an example to show that contravariant function return type is not type safe. [2 marks]

class Animal {} class Cat : public Animal {}

struct CatShelter { virtual Cat * adopt(); };

struct AnimalShelter : public CatShelter { virtual Animal * adopt(); };

CatShelter * cs = new AnimalShelter(); Cat * cat = cs->adopt(); // type-unsafe, Animal may not be a Cat

2. What is the value of the following expression? What is the name of the behaviour? Assume the integer is 32-. [2 marks]

int a = 1 << 31; printf(“%d”, -a);

-2147483648 (a == -a) Overflow 3. Write a safe C macro, CIRCLE_AREA, that takes one parameter and will calculate the radius of a circle. You also need to define the constant PI. [3 marks]

#define PI 3.14159 #define CIRCLE_AREA(r) PI*(r)*(r) /* better yet (GNU C extension) */ #define CIRCLE_AREA(r) ({ typeof(r) _r = (r); PI*_r*_r; })

4. Write the precondition and postcondition for the square root function, sqrt() that takes in a double and returns a double. Suppose Complex is a subclass of double, what’s the variance relationship between double sqrt(double) and Complex sqrt(Complex)? [3 marks]

Let n be the parameter to sqrt, i.e. sqrt(double n), and r be the return value Precondition: n >= 0 Postcondition: n >= 0 (if only the principle square root is returned) Covariant parameter, covariant return type. Note that both parameter and return type are problematic because covariant parameter is not type safe, and the postcondition of sqrt() is weakened, which violates Liskov’s substitution principle.

3. [10 marks]

Complete the implementation of the tagged union example from class by adding a copy constructor, overload the equality operator, and type-safe getter/setter function

struct Tagged { enum { INT, STR } tag; union { // anonymous union (members int * i; // can enter parent scope) string * s; }; Tagged(int i) : tag(INT), i(new int(i)) {} Tagged(const char * s) : tag(STR), s(new string(s)) {} ~Tagged() { if (tag == INT) delete i; else delete s; }

Tagged(const Tagged & rhs) {

}

bool operator==( const Tagged & rhs) {

}

const string * get_str() const {

}

void set_str(const string & s) {

} }; see solution file (union.cpp) ECE326 – Fall 2019: Week 8 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. C macro functions always produce syntactically correct C/C++ code. T F

2. Once a macro is used, it cannot be used during the same macro expansion. T F

3. To prevent infinite recursion, it is not possible for concatenation to form a token that can be used as a macro. T F

4. The main benefit of optional compilation over inheritance is performance (speed). T F Executable size is the main benefit. Optional compilation does not significantly improve performance except possibly due to less cache miss. Code organization can be another benefit. 5. Clever use of C preprocessor macro allows for static introspection. T F Preprocessor have no knowledge of host language. 6. A constexpr function or variable is exclusively for compile-time use. T F

2. Generic Programming [10 marks]

Use C macros instead of template programming to generate a Stack class of generic element type. Your stack should be type safe and should have the pop and push member functions. Assume input will be an unadorned type (not a pointer, not a reference, not const or other qualifiers).

// creates a class named IntStack with integer elements DEFINE_STACK(IntStack, int);

// creates a class named ComplexStack with Complex elements DEFINE_STACK(ComplexStack, Complex);

see macro.cpp

3. Compile-Time String [10 marks]

Write a compile-time class, ConstStr, which provides the following three compile-time methods: 1) hash(), which returns a djb2 hash of the string (http://www.cse.yorku.ca/~oz/hash.html), 2) startswith(substr), which only returns true if the string starts with the substring substr, and 3) endswith(substr), which only returns true if the string ends with the substring substr.

see conststr.cpp

4. C Macro [5 marks]

The PP_NARG macro can count the number of arguments that is passed into the maco function. However, it doesn’t work correctly if no arguments are passed in. Fix the macro so that it also supports no arguments.

#define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N()) #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__) #define PP_ARG_N( _1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N #define PP_RSEQ_N() 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 see macro.cpp

ECE326 – Fall 2019: Week 9 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. Type traits in C++ is an example of reflective programming. T F

Static introspection is part of reflective programming.

2. Unevaluated context means the expression cannot be evaluated (i.e. is ill-formed). T F It means the expression is only used at compile time and not evaluated at runtime. 3. To use an integer vector iterator inside a template, the type of the iterator is specified as typename vector::iterator. T F

4. C++ type checks code even if it is unreachable. T F

5. Non-template functions that take variable number of arguments have precedence over base template functions that accepts any type T. T F

2. rm_const [5 marks]

Complete the implementation of rm_const, which remove const from type T if T is const-qualified (meaning that const is part of T, e.g. const int).

// becomes int cout << std::is_const::type>::value << endl;

// still int cout << std::is_const::type>::value << endl;

See isptr.cpp 3. is_ptr [7 marks]

Complete the implementation of is_ptr, which checks whether the type T is a pointer or not. You must be able to a const pointer (e.g. int * const). Hint: rm_const may be helpful.

template is_ptr; cout << is_ptr::value << endl; // 0 cout << is_ptr::value << endl; // 1 cout << is_ptr::value << endl; // 1 cout << is_ptr::value << endl; // 0 cout << is_ptr::value << endl; // 1

See isptr.cpp

4. can_equate [5 marks]

Write a C++ template, can_equate, which checks whether type T can be equal to type U. You must handle the situation when either T or U overloads the == operator.

See equate.cpp

ECE326 – Fall 2019: Week 10 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. It is not possible to cause infinite recursion when working with variadic template. T F

2. In general, arguments to variadic functions are not type-checked. T F

3. In Rust, name aliasing is not allowed. T F

4. Rust is strongly typed. T F

5. In Rust, ownership is a mechanism to check for memory leaks at runtime. T F

6. The major disadvantage of Rust is that it automatically adds runtime type safety checks, which negatively affects its runtime performance. T F

2. Short Answer [5 marks]

What’s the difference between the following two sets of statements?

// 1 let x = 5; let x = x + 2; let x = x * 3;

// set 2 let mut x = 5; x = x + 2; x = x * 3;

Set 1 uses shadowing of immutable variables. The last x is the only variable that can be accessed after that statement.

Set 2 uses a single mutable variable.

3. Variadic Template [10 marks]

Write a variadic template that calculates the population variance of a set of values. The return type of the template should always be double, but the template arguments can take any numeric type. https://en.wikipedia.org/wiki/Variance

See variance.cpp ECE326 – Fall 2019: Week 11 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. In Rust, literals are first class citizens. T F

2. Box forces the contained object to be heap allocated. T F

3. A mutable object can be modified even if an immutable reference of it is in scope. T F

4. After transferring ownership, an can become mutable. T F

5. Generics in Rust supports duck typing. T F

2. Match [10 marks]

Create a function named hand_score which takes a tuple of two characters and returns the score of a blackjack hand using ONLY the match expression. You need to handle soft hands (e.g. A8 = 19) and hard hands. Return 21 for Blackjack. Assume the card values have been sanitized (do not check for invalid card). Hint: is_digit() and to_digit() may be helpful. https://doc.rust-lang.org/std/primitive.char.html

fn hand_score(hand: (char, char)) -> u32

3. Structure and Method [20 marks]

Write structure named Matrix which supports a 2x2 matrix of type f64, and implements the determinant method, the transpose method, and the inverse method. The transpose method should modify the existing matrix, but the inverse method should return a new matrix if the matrix is invertible, otherwise it should return None (Hint: use Option). Write a new static method which creates and initializes the matrix. Implement the Display trait for Matrix.

4. Generic Function [10 marks]

Write a generic function, sum_of_squares, which calculates the sum of squares of a generic array slice. Hint: you may need some trait bounds. ECE326 – Fall 2019: Week 12 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. Lifetime parameter must be added to all structures with non-static references. T F

2. Lifetime elision optimizes the binary by eliminating the need to copy parameters. T F

3. Concurrent programming helps reduce bugs by organizing code into independent threads of execution. T F

4. On a uniprocessor, it is safe to use Rc instead of Arc. T F

5. In Java, the synchronized operator enables synchronization between threads. T F

2. Channel [10 marks]

Use mpsc::channel and multiple threads to improve the performance of large square matrix multiplication.

3. Dining Philosopher [10 marks]

In the dining philosopher problem, there are N philosophers and N chopsticks in between each pair of philosophers. As you may know, you need a pair of chopsticks to be able to eat. A philosopher must successfully acquire both chopsticks to his/her left and right before proceeding to eat. Simulate this problem by creating one per philosopher, and use a monitor to synchronize the use of chopsticks.

4. Findall [10 marks]

Write a function that takes two string slices, text and word, and return a vector of all occurrences of the word in text in string slices. Note, you may need to “fix” the function signature. You may assume the text to consist of only ascii characters.

fn findall(text: &str, word: &str) -> Vec<&str>; ECE326 – Fall 2019: Week 13 Exercise Questions

1. True or False [1 mark each]

Circle T is true, otherwise circle F for false.

1. Trait objects can only be created on the heap. T F

2. Both C++ and Rust allows specifying the return type of arithmetic operations. T F

3. Generally speaking, a chain of iterator adapters should end in collect or fold. T F

4. In C++, closures and functions can be used interchangeably. T F

5. In a multithreaded setting, mutually recursive functions must implement mutual exclusion. T F

6. A generator cannot have the return statement. T F

2. Average of Shapes [10 marks]

Implement the Shape trait for Rectangle, Circle, and Triangle. The Shape trait has one method, area, which returns the area of the shape. Write a function which takes a list of shapes and returns the average area.

fn average_area(list: &Vec>) -> f64;

3. Coroutine [10 marks]

Write a Python function, ppmt, which returns the payment on principal for a given period for a loan based on periodic, constant payments and a constant interest rate. In addition, at any time, the user can make either lump sum payment or take out additional loan, which would cause the next payment to change based on remaining period.

# rate: interest rate (e.g. 0.0375 for 3.75% per period) # per: number of periods # pv: initial principal value on loan def ppmt(rate, per, pv)

loan = ppmt(0.0375, 240, 1000000) first_payment = next(loan) # e.g. taking out additional loan second_payment = loan.send(50000)