# PHAS0100 - week 4
### 2pm-5pm Friday 4th February
:::info
## :tada: Welcome to the 4th live-class!
#### Reminder: both groups are now merged into this Friday class
### Today
Today we will learn about
- Dependency injection and programming to interfaces
- The RAII pattern: aquire resources in constructor,
- Templates: function template, class templates, template specialisation
- 💻 :ok_hand:
:::
### Timetable for this afternoon
| Start | End | Topic |
| -------- | -------- | -------- |
| 14:05 | 14:35 | Lecture part 1: Dependency injection, program to interfaces, RAII |
| 14:35 | 14:55 | Breakout/coding: Excercise 19 |
| 15:55 | 15:05 | Break | --- |
| 15:05 | 15:30 | Breakout/coding: Excercise 19 (cont) and exercise 20 |
| 15:30 | 15:55 | Lecture part 2: Function and class templates |
| 15:55 | 16:05 | Break | --- |
| 16:05 | 16:45 | Breakout/coding: Exercise 21 |
| 16:45 | 16:55 | Summary and closeout |
Exercises 22 and 23 are the homework exercises for this week.
### Project templates
<details>
- [CMakeHelloWorld](https://github.com/UCL/CMakeHelloWorld) - Single `.cpp` file
- [CMakeLibraryAndApp](https://github.com/UCL/CMakeLibraryAndApp) - Multiple `.h` and `.cpp` files
- [CMakeCatch2](https://github.com/UCL/CMakeCatch2) - Includes Catch, example library (Eigen) and separate compilation of library and application
</details>
## Breakout session 1
## Class Exercise 19
In this session you will be trying out the two types of dependency injection: constructor dependency injection and setter dependency injection.
* Building on the `Student` class from homework 17 ([Solution](https://hackmd.io/c0qe_VL1Qk2tSfaYDkgkyw?view#Solution4)):
* Create a new `Laptop` class that has a string `os` data member for the operating system name and an integer `year` data member for the year produced.
* `Laptop` should have both a default constructor that sets `year` to 0 and name to "Not set" as well as a constructor that takes two arguments to set `year` and `os`
* Modify `Student` to have a `std::unique_ptr` to a `Laptop` as a private data member
* Implement the two types of dependency injection for the `Student` class: constructor, setter
* Confirm that the `Student` class is now invarient to changes in how you instantiate `Laptop`
* Discuss how and why you might implement an abstract interface class for the types of objects a Student owns
_This exercise may spill over into breakout 2. Class exercise 20 is quicker_
#### Solution
<details>
You could use CMakeLibraryAndApp as a starting point.
The Laptop class should have multiple ways in which it can be constructed or configured. Here we just provide a default constructor (no arguments) and a constructor that allows `os` and `year` to be set. The `Laptop` class `Laptop.h` header file:
```cpp=
#ifndef Laptop_h
#define Laptop_h
#include <string>
class Laptop {
public:
Laptop();
Laptop(const std::string& os, const int& year);
~Laptop();
void SetOSYear(const std::string& os, const int& year);
void Print();
private:
std::string os_;
int year_;
};
#endif
```
`Laptop.cpp` implementation file:
```cpp=
#include "Laptop.h"
#include <iostream>
//--------------------------------------------------------------------
Laptop::Laptop()
{
os_ = "Not set";
year_ = 0;
// do other stuff to setup
}
//--------------------------------------------------------------------
Laptop::Laptop(const std::string& os, const int& year)
{
os_ = os;
year_ = year;
// do other stuff to setup
}
//--------------------------------------------------------------------
Laptop::~Laptop(){
// do stuff to cleanup
}
//--------------------------------------------------------------------
void Laptop::SetOSYear(const std::string& os, const int& year)
{
os_ = os;
year_ = year;
}
//--------------------------------------------------------------------
void Laptop::Print()
{
std::cout << os_ << " ("<< year_ << ")" << std::endl;
}
```
The `Student` class has a dependency on the `Laptop` class as has a data member pointing to a `Laptop` instance. We pass (inject) this dependency into the `Student` class.
The Student class needs a constructor that accepts a pointer (we use a unique_ptr to avoid using raw pointers, see Week 3) to an already created Laptop instance to demonstrate constructor dependency injection. As well as a setter method to pass a Laptop pointer to demonstrate setter dependency injection. Student class `Student.h` header file:
```cpp=
#ifndef Student_h
#define Student_h
#include "Laptop.h"
#include <memory>
#include <string>
class Student {
public:
Student(std::string name, int age);
Student(std::unique_ptr<Laptop> laptop, \
std::string name, int age);
~Student();
void SetLaptop(std::unique_ptr<Laptop> laptop);
void Print();
private:
std::string name_;
int age_;
std::unique_ptr<Laptop> laptop_;
};
#endif
```
And the `Student.cpp` implementation file:
```cpp=
#include "Student.h"
#include <utility> // std::move
#include <iostream>
//--------------------------------------------------------------------
Student::Student(std::string name, int age)
{
name_ = name;
age_ = age;
// do other stuff to setup
}
//--------------------------------------------------------------------
Student::Student(std::unique_ptr<Laptop> laptop, std::string name, int age)
{
laptop_ = std::move(laptop);
name_ = name;
age_ = age;
}
//--------------------------------------------------------------------
Student::~Student()
{
// do stuff to cleanup
}
//--------------------------------------------------------------------
void Student::SetLaptop(std::unique_ptr<Laptop> laptop)
{
laptop_.swap(laptop);
// laptop_ = std::move(laptop);
}
//--------------------------------------------------------------------
void Student::Print()
{
std::cout << name_ << ", "<< age_ << ", ";
if(laptop_){
laptop_->Print();
}
}
```
The following `myStudentApp.cpp` application then demonstrates the different types of dependency injection:
```cpp=
#include "Student.h"
#include "Laptop.h"
#include <memory>
#include <utility>
int main(){
// Constructor dependency injection
auto windows = std::make_unique<Laptop>("Windows 10 Home", 2020);
Student juliet(std::move(windows), "Juliet", 101);
juliet.Print();
// Setter dependency injection
auto mac = std::make_unique<Laptop>("OSX", 2019);
Student john("John", 100);
john.SetLaptop(std::move(mac)); // note move required as it is a unique_ptr
john.Print();
// Construct/configure Laptop differently
auto ubuntu = std::make_unique<Laptop>();
ubuntu->SetOSYear("Ubuntu 20.04", 2021);
// No change to Student.cpp/.h required
Student jerome(std::move(ubuntu), "Jerome", 102); // Constructor dependency injection
jerome.Print();
return 0;
}
```
Example `CMakeLists.txt` lines for above if working from CMakeLibraryAndApp:
```cmake=
set (CMAKE_CXX_STANDARD 17)
add_library(Student Student.cpp)
add_library(Laptop Laptop.cpp)
add_executable(myStudentApp myStudentApp.cpp)
target_link_libraries(myStudentApp Student Laptop)
```
Main points for discussion:
* If you used programming to interfaces and defined an abstract interface class `ResourceI` with methods like `virtual int GetYear() = 0;` and `virtual int GetName() = 0;`
* You could then have concrete derived classes of different types of resources like `Laptop` and `Book` and `Video` stored in a container of `std::vector<std::unique_ptr<ResourceI> >` in the `Student` class.
* And implement general methods in `Student` to add resources and print a summary of all resources, for example.
* The implementation of `Student` would not need to be changed even you create new concrete derived types of `ResourceI`.
</details>
## Breakout session 2
## Class Exercise 20
In this session you will implement a container class following the RAII (Resource Aquisition Is Initialisation) pattern: all resources aquired in the constructor and all resources released in the destrurctor.
* Create a simple class `FooAllocator` that contains a data member that is a raw pointer `foo_ptr` to another class `Foo`
* Add a `std::cout` to the constructor and destructor of both classes so that you know when they have been called
* Create function `void AFunctionThatThrows()` that creates a `FooAllocator` object and then throws an exception before reaching the end of the fuction
* Confirm that the destructor for both the `FooAllocator` and `Foo` objects are called as long as the exception is caught in the calling code
* Discuss how you would implement using`std::unique_ptr` instead of a raw pointer?
* i.e. how would the implementation differ if FooAllocator stored a `std::unique_ptr`? What if FooAllocator stored another type of resource, for example a `std::ofstream` for writing to files?
#### Solution
<details>
For simplicity implement in a single `myRAIIExample.cpp` application file:
```cpp=
#include <iostream>
#include <stdexcept>
using std::cout;
using std::endl;
// Dummy Foo class to indicate when constructed/destroyed
class Foo
{
public:
Foo(){ cout << "Foo()" << endl; }
~Foo(){ cout << "~Foo()" << endl;}
};
// FooAllocator implement RAII for a Foo
class FooAllocator
{
public:
FooAllocator() // acquire resource in constructor
{
cout << "FooAllocator()" << endl;
foo_ptr_ = new Foo(); // just an example, in general use smart pointers and avoid new
}
~FooAllocator() // release resource in destructor
{
cout << "~FooAllocator()" << endl;
delete foo_ptr_;
}
private:
Foo * foo_ptr_;
};
// A function that creats a FooAllocator and then throws exception
void FunctionThatThrows(){
FooAllocator f;
throw std::runtime_error("Something is wrong");
}
// Simple main to show the Foo's destructor is called
int main(){
try {
FunctionThatThrows();
}
catch (std::exception& e){
std::cout << "Caught exception: "<< e.what() << std::endl;
}
return 0;
}
```
And then add the following to your CMakeLists.txt:
```cmake
add_executable(myRAIIExample myRAIIExample.cpp)
```
Main points for discussion:
* The FooAllocator implements similar behaviour to `std::unique_ptr`
* If you were to store the `Foo` data member as a `std::unique_ptr<Foo>` in the FooAllocator or other class that owns it then you would not need to call the destructor `delete foo_ptr_` in ~FooAllocator
* If the resource you are using implements RAII then no need to explicitly call destructor in class using it - this is the case for `std::ofstream`
</details>
## Breakout session 3
In this session you'll try defining and instantiating some of your own function templates and class templates: trying out implicit vs explicit instantiation and working through an example where you provide a template specialisation for a specific type.
## Class Exercise 21
* Review the general syntax for a function template: `template <typename T> T sum(T a, T b);`
* Then implement the `template <typename T> T sum(T a, T b);` example from the notes (slide number 31):
* Try out both explicit and implicit instantiation
#### Solution
<details>
The general form for a template function is
`template < parameter-list > function-declaration`
* The `template` keyword tells the compiler we are declaring or defining a template
* The parameter list names the types that the template will use - you can use the `typename` or `class` keywords when defining a type although we recommend `typename` to avoid confusion with class definitions
* An example template parameter would be`typename T1`. Here the name `T1` is arbitrary. You can think of it as an alias for a future type that will be supplied to the template function when it is instantiated
* Then the `function-declaration` declares the function to be templated - this function can treat `T1` as if it is a type: it could manipulate variables of type T1, return a type T1, take type T1 variables as arguments
Take the `sum` function template from the Week 4 slides. The following should go in a header `.h` file and it defines a `sum` function and the logic to sum two inputs together based on a generic type `T` that will be supplied later on when the template is instantiated:
```cpp
template <typename T> // typename|class
T sum (T a, T b)
{
T result;
result = a + b;
return result;
}
```
which could then be instantiated in the main application as:
```cpp
double a = 1.5;
double b = 2.0;
// implicitly instantiates sum<double>(double a, double b)
std::cout << sum(a, b) << std::endl; // outputs 3.5
// explicitly instantiates sum<int>(static_cast<int>(a), static_cast<int>(b))
std::cout << sum<int>(a, b) << std::endl; // outputs 3
```
* Here we can see that the logic in the `sum` function can be reused for any variable or type as long as the `+` operator is defined for it
</details>
## Homework Exercise 22
_If there is time in the class can make a start on this_
Write a template function `TLists RemoveMatching(TElement element, TList l)` that searches a vector or list for elements matching `element` and returns a new `TList` with those elements removed
* Try out both explicit and implicit instantiation
* Write a template specialisation for `RemoveMatching` for the case where `TElement` is a `char` and `TList` is a `std::string`
#### Solution
<details>
The following template definitions could go in a `RemoveMatching.h` header file that is then `#include RemoveMatching.h`'d in your main app:
```cpp
// Returns a new list with all matching elements removed
template<typename TElement, typename TList>
TList RemoveMatching(TElement match, TList list)
{
TList new_list;
for(auto element : list){
if(element != match)
{
new_list.push_back(element);
}
}
return new_list;
}
// For convenience also define a Print template function
template<typename T>
void Print(T array)
{
for(auto entry : array)
{
std::cout << entry << " ";
}
std::cout << "\n";
}
```
Then some examples of how to instantiate the function template are:
```cpp
std::vector<int> v{1,20,40,50};
// Implicit instantiation
auto v2 = RemoveMatching(20, v);
Print(v2); // outputs: 1 40 50
// Explicit instantiation
auto v3 = RemoveMatching<int, std::vector<int>>(40, v);
print(v3); // outputs: 1 20 50
std::list<std::string> l{"A","BB","CCC","DDD"};
// Implicit instantiation
auto l2 = RemoveMatching("CCC", l);
Print(l2); // outputs A BB DDD
// Explicit instantiation for std::list but now try to pass
// it a vector of int's - the following will not compile
// auto l3 = RemoveMatching<std::string, std::list<std::string> >(20, v);
```
</details>
## Class Exercise 23
* Review the general syntax for a class template:
`template < parameter-list > class-declaration`
* Implement the `MyPair` class template from the week 4 slides
* Try using with both Implicit and Explicit instantiation
#### Solution
<details>
Compare the general syntax for a class template:
`template < parameter-list > class-decaration`
to the specific `MyPair` example from the notes (Week 4, slide number 45):
In `pairClassExample.h`
```cpp
template <typename T>
class MyPair
{
T m_Values[2];
public:
MyPair(const T &first, const T &second); T getMax() const;
};
#include "pairClassExample.cc" // include .cc file in header file just for templates
```
* Note the similarities with the function template syntax: `template < parameter-list >` followed by function or class declaration.
Then in `pairClassExample.cc`
```cpp
template <typename T>
MyPair<T>::MyPair(const T& first, const T& second)
{
m_Values[0] = first;
m_Values[1] = second;
}
template <typename T>
T MyPair<T>::getMax() const
{
if (m_Values[0] > m_Values[1])
return m_Values[0];
else
return m_Values[1];
}
```
Then in the main app:
```cpp
// Explicit instantiation
MyPair<int> a(1,2);
std::cout << "Max is:" << a.getMax() << std::endl;
// outputs 2.0
// Implicit instantiation
MyPair b(3.0, 4.5);
std::cout << "Max is:" << b.getMax() << std::endl;
// outputs 4.5
// Explicit <int> but now passing double that get static_cast
MyPair<int> c(1.9,2.9);
std::cout << "Max is:" << c.getMax() << std::endl;
// outputs 2
```
</details>
### Homework Exercise - 24
Extend the MyPair class with two new methods:
* A `void printValues()` method that prints to screen the typeid of the class T which for which the template has been instantiated as well as the values of m_Values[0] and m_Values[1]
* A `void swapValues()` method that uses `std::swap` to swap the elements
#### Solution
<details>
The `pairClassExample.h` would have the following methods declarations added:
``` cpp
template <typename T>
class MyPair
{
T m_Values[2];
public:
MyPair(const T &first, const T &second);
T getMax() const;
void swapValues();
void printValues();
};
#include "pairClassExample.cc"
```
and `pairClassExample.cc` has the following definitions added:
```cpp=
template <typename T>
void MyPair<T>::swapValues()
{
std::swap(m_Values[0], m_Values[1]);
}
template <typename T>
void MyPair<T>::printValues()
{
std::cout << typeid(T).name() << ": " << m_Values[0] << " " << m_Values[1] << std::endl;
}
```
then in the main function you could check with:
```cpp
MyPair b(3.0, 4.5);
b.printValues(); // outputs "d: 3 4.5"
MyPair<int> c(1.9,2.9);
c.printValues(); // outputs "i: 1 2
c.swapValues();
c.printValues(); // outputs "i: 2 1"
```
</details>
# Questions
Here you can post any question you have while we are going through this document. A summary of the questions and the answers will be posted in moodle after each session. Please, use a new bullet point for each question and sub-bullet points for their answers.
For example writing like this:
```
- Example question
- [name=student_a] Example answer
- [name=TA_1] Example answer
```
produces the following result:
- Example question
- [name=student_a] Example answer
- [name=TA_1] Example answer
Write new questions below :point_down:
- []
- [name=TA_1] Example answer
###### tags: `phas0100` `teaching` `class`