type safety and std::optional
TRANSCRIPT
![Page 1: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/1.jpg)
Type Safety and std::optional
How can we use c++’s type system to prevent errors at compile
time?
![Page 2: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/2.jpg)
Recap: Const-Correctness- We pass big pieces of data by reference into helper functions
by to avoid making copies of that data
- If this function accidentally or sneakily changes that piece of
data, it can lead to hard to find bugs!
![Page 3: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/3.jpg)
Why const? Overly ambitious functions in application codelong int countPopulation(Planet& p) {
// Hats are the cornerstone of modern society
addLittleHat(p);
return p.count_population();
}
![Page 4: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/4.jpg)
Why const? Overly ambitious functions in application codelong int countPopulation(Planet& p) {
// Hats are the cornerstone of modern society
addLittleHat(p);
// Guaranteed no more population growth, all future calls will be faster
sterilize(p);
return p.count_population();
}
![Page 5: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/5.jpg)
Why const? Overly ambitious functions in application codelong int countPopulation(Planet& p) {
// Hats are the cornerstone of modern society
addLittleHat(p);
// Guaranteed no more population growth, all future calls will be faster
sterilize(p);
// Optimization: destroy planet
// This makes population counting very fast
deathStar(p);
return 0;
}
![Page 6: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/6.jpg)
Recap: Const-Correctness- We pass big pieces of data by reference into helper functions
by to avoid making copies of that data
- If this function accidentally or sneakily changes that piece of
data, it can lead to hard to find bugs!
- Solution: mark those reference parameters const to
guarantee they won’t be changed in the function!
![Page 7: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/7.jpg)
Why const? Overly ambitious functions in application codelong int countPopulation(const Planet& p) {
// Hats are the cornerstone of modern society
addLittleHat(p); //compile error
// Guaranteed no more population growth, all future calls will be faster
sterilize(p); //compile error
// Optimization: destroy planet
// This makes population counting very fast
deathStar(p); //compile error
return 0;
}
![Page 8: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/8.jpg)
How does this work?long int countPopulation(const Planet& p) {
// Hats are the cornerstone of modern society
addLittleHat(p); //compile error
...
}
void addLittleHat(Planet& p) {
p.add(👒);
} p is a (non const) reference here
p is a const reference hereCalling addLittleHat on p is
like setting a non const variable equal to a const
one, it’s not allowed!
![Page 9: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/9.jpg)
How does the compiler know when it’s safe to call member functions of const variables?
![Page 10: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/10.jpg)
const-interface: All member functions marked const in a class definition. Objects of type const ClassName may only use the const-interface.
Definition
![Page 11: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/11.jpg)
template<class ValueType> class RealVector {public: using iterator = ValueType*; using const_ iterator = const ValueType*; /*...*/ size_t size() const; bool empty() const; /*...*/ void push_back(const ValueType& elem);
iterator begin();iterator end();
const_iterator cbegin()const; const_iterator cend()const;
/*...*/
RealVector’s const-interface
![Page 12: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/12.jpg)
Key Idea: Sometimes less functionality is better functionality- Technically, adding a const-interface only limits what
RealVector objects marked const can do
- Using types to enforce assumptions we make about function
calls help us prevent programmer errors!
![Page 13: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/13.jpg)
Type Safety: The extent to which a language prevents typing errors.
Definition
![Page 14: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/14.jpg)
Recall: Python vs C++
def div_3(x):
return x / 3
div_3(“hello”)
//CRASH during runtime,
can’t divide a string
int div_3(int x){
return x / 3;
}
div_3(“hello”)//Compile error: this code will
never run
Python C++
![Page 15: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/15.jpg)
Type Safety: The extent to which a language guarantees the behavior of programs.
Definition
![Page 16: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/16.jpg)
What does this code do?
void removeOddsFromEnd(vector<int>& vec){while(vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 17: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/17.jpg)
What does this code do?
What happens when input is {} ?
void removeOddsFromEnd(vector<int>& vec){while(vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 18: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/18.jpg)
code
![Page 19: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/19.jpg)
std::vector documentation
Undefined behavior: Function could crash, could give us garbage,
could accidentally give us some actual value
![Page 20: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/20.jpg)
What does this code do?
We can make no guarantees about what this function does!
Credit to Jonathan Müller of foonathan.net for the example!
void removeOddsFromEnd(vector<int>& vec){while(vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 21: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/21.jpg)
One solution
void removeOddsFromEnd(vector<int>& vec){while(!vec.empty() && vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 22: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/22.jpg)
One solution (also the status quo)
Key idea: it is the programmers job to enforce the precondition
that vec be non-empty, otherwise we get undefined behavior!
void removeOddsFromEnd(vector<int>& vec){while(!vec.empty() && vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 23: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/23.jpg)
There may or may not be a “last element” in vec
How can vec.back() have deterministic behavior in either case?
![Page 24: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/24.jpg)
The problem
Dereferencing a pointer without verifying it points to real
memory is undefined behavior!
valueType& vector<valueType>::back(){return *(begin() + size() - 1);
}
![Page 25: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/25.jpg)
The problem
Now, we will at least reliably error and stop the program or
return the last element whenever back() is called
valueType& vector<valueType>::back(){if(empty()) throw std::out_of_range;return *(begin() + size() - 1);
}
![Page 26: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/26.jpg)
Deterministic behavior is great, but can we do better?
There may or may not be a “last element” in vecHow can vec.back() warn us of that when we
call it?
![Page 27: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/27.jpg)
Type Safety: The extent to which a function signature guarantees the behavior of a function.
Definition
![Page 28: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/28.jpg)
The problem
back() is promising to return something of type valueType
when its possible no such value exists!
valueType& vector<valueType>::back(){return *(begin() + size() - 1);
}
![Page 29: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/29.jpg)
A first solution?
back() now advertises that there may or may not be a last
element
std::pair<bool, valueType&> vector<valueType>::back(){if(empty()){
return {false, valueType()};}return {true, *(begin() + size() - 1)};
}
![Page 30: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/30.jpg)
Problems with using std::pair<bool, valueType&>
- valueType may not have a default constructor
std::pair<bool, valueType&> vector<valueType>::back(){if(empty()){
return {false, valueType()};}return {true, *(begin() + size() - 1)};
}
![Page 31: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/31.jpg)
Problems with using std::pair<bool, valueType&>
- valueType may not have a default constructor
- Even if it does, calling constructors is expensive
std::pair<bool, valueType&> vector<valueType>::back(){if(empty()){
return {false, valueType()};}return {true, *(begin() + size() - 1)};
}
![Page 32: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/32.jpg)
Problems with using std::pair<bool, valueType&>
This is still pretty unpredictable behavior! What if the default
constructor for an int produced an odd number?
void removeOddsFromEnd(vector<int>& vec){while(vec.back().second() % 2 == 1){
vec.pop_back();}
}
![Page 33: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/33.jpg)
What should back() return???? vector<valueType>::back(){
if(empty()){return ??;
}return *(begin() + size() - 1);
}
![Page 34: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/34.jpg)
Introducing std::optional
![Page 35: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/35.jpg)
What is std::optional<T>?- std::optional is a template class which will either contain a value of type T
or contain nothing (expressed as nullopt)
![Page 36: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/36.jpg)
What is std::optional<T>?- std::optional is a template class which will either contain a value of type T
or contain nothing (expressed as nullopt)
void main(){std::optional<int> num1 = {}; //num1 does not have a valuenum1 = 1; //now it does!num1 = std::nullopt; //now it doesn't anymore
}
![Page 37: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/37.jpg)
What if back() returned an optional?std::optional<valueType> vector<valueType>::back(){
if(empty()){return {};
}return *(begin() + size() - 1);
}
![Page 38: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/38.jpg)
How would it look to use back()?
This would not compile!
void removeOddsFromEnd(vector<int>& vec){while(vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 39: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/39.jpg)
How would it look to use back()?
We can’t do arithmetic with an optional, we have to get the value
inside the optional (if it exists) first!
void removeOddsFromEnd(vector<int>& vec){while(vec.back() % 2 == 1){
vec.pop_back();}
}
![Page 40: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/40.jpg)
std::optional interface- .value()
returns the contained value or throws bad_optional_access
error
- .value_or(valueType val)
returns the contained value or default value, parameter val
- .has_value()
returns true if contained value exists, false otherwise
![Page 41: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/41.jpg)
Checking if an optional has value...std::optional<Student> lookupStudent(string name){//something}
std::optional<Student> output = lookupStudent(“Keith”);
if(student.has_value()){cout << output.value().name << “ is from “ <<
output.value().state << endl;} else { cout << “No student found” << endl;}
![Page 42: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/42.jpg)
Evaluate optionals for a value like bools!std::optional<Student> lookupStudent(string name){//something}
std::optional<Student> output = lookupStudent(“Keith”);
if(student){cout << output.value().name << “ is from “ <<
output.value().state << endl;} else { cout << “No student found” << endl;}
![Page 43: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/43.jpg)
How would it look to use back()?
Now, if we access the back of an empty vector, we will at least
reliably get the bad_optional_access error
void removeOddsFromEnd(vector<int>& vec){while(vec.back().value() % 2 == 1){
vec.pop_back();}
}
![Page 44: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/44.jpg)
How would it look to use back()?
This will no longer error, but it is pretty unwieldy :/
void removeOddsFromEnd(vector<int>& vec){while(vec.back().has_value() && vec.back().value() % 2 == 1){
vec.pop_back();}
}
![Page 45: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/45.jpg)
How would it look to use back()?
Better?
void removeOddsFromEnd(vector<int>& vec){while(vec.back() && vec.back().value() % 2 == 1){
vec.pop_back();}
}
![Page 46: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/46.jpg)
How would it look to use back()?
Totally hacky, but totally works ;)
void removeOddsFromEnd(vector<int>& vec){while(vec.back().value_or(2) % 2 == 1){
vec.pop_back();}
}
![Page 47: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/47.jpg)
How would it look to use back()?
Totally hacky, but totally works ;) don’t do this ;)
void removeOddsFromEnd(vector<int>& vec){while(vec.back().value_or(2) % 2 == 1){
vec.pop_back();}
}
![Page 48: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/48.jpg)
Recap: The problem with std::vector::back()- Why is it so easy to accidentally call back() on empty
vectors if the outcome is so dangerous?
- The function signature gives us a false promise!
- Promises to return an something of type valueType
- But in reality, there either may or may not be a “last element”
in a vector
valueType& vector<valueType>::back()
![Page 49: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/49.jpg)
Code demo: An optional take on realVector
![Page 50: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/50.jpg)
Is this...good?Pros of using std::optional returns:
- Function signatures create more informative contracts
- Class function calls have guaranteed and usable behavior
Cons:
- You will need to use .value() EVERYWHERE
- (In cpp) It’s still possible to do a bad_optional_access
- (In cpp) optionals can have undefined behavior too (*optional does same thing as
.value() with no error checking)
![Page 51: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/51.jpg)
More bad code
What happens if vec is empty? More undefined behavior!
int thisFunctionSucks(vector<int>& vec){return vec[0];
}
![Page 52: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/52.jpg)
Implementation of vector [] operator
What happens if vec is empty? More undefined behavior!
valueType& vector<valueType>::operator[](size_t index){return *(begin() + index);
}
![Page 53: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/53.jpg)
std::optional<T&> is not available!
The underlying memory implications actually get very complicated...
std::optional<valueType&> vector<valueType>::operator[](size_t index){
return *(begin() + index);}
![Page 54: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/54.jpg)
Best we can do is error..which is what .at() does
🤔 Why have both?
valueType& vector<valueType>::operator[](size_t index){return *(begin() + index);
}valueType& vector<valueType>::at(size_t index){
if(index >= size()) throw std::out_of_range;return *(begin() + index);
}
![Page 55: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/55.jpg)
Is this...good?Pros of using std::optional returns:
- Function signatures create more informative contracts
- Class function calls have guaranteed and usable behavior
Cons:
- You will need to use .value() EVERYWHERE
- (In cpp) It’s still possible to do a bad_optional_access
- (In cpp) optionals can have undefined behavior too (*optional does same thing as
.value() with no error checking)
- In a lot of cases we want std::optional<T&>...which we don’t have
![Page 56: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/56.jpg)
Why even bother with optionals?
![Page 57: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/57.jpg)
std::optional “monadic” interface (C++23 sneak peek!)- .and_then(function f)
returns the result of calling f(value) if contained value exists,
otherwise null_opt (f must return optional)
- .transform(function f)
returns the result of calling f(value) if contained value exists,
otherwise null_opt (f must return optional<valueType>)
- .or_else(function f)
returns value if it exists, otherwise returns result of calling f
![Page 58: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/58.jpg)
Code might look like this...std::optional<Student> lookupStudent(string name){//something}
std::optional<Student> output = lookupStudent(“Keith”);
auto func = (std::optional<Student> stu)[] {
return stu ? stu.value().name + “is from “ +
to_string(stu.value().state) : {};
}
cout << output.and_then(func).value_or(“No student found”);
![Page 59: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/59.jpg)
How would it look to use back()?void removeOddsFromEnd(vector<int>& vec){
auto isOdd = [](optional<int> num){return num ? (num % 2 == 1) : {}
};while(vec.back().and_then(isOdd)){
vec.pop_back();}
}
![Page 60: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/60.jpg)
Why std::vector::back() doesn’t return an optional(and probably never will)
![Page 61: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/61.jpg)
Recall: Design Philosophy of C++
61
- Only add features if they solve an actual problem
- Programmers should be free to choose their own style
- Compartmentalization is key
- Allow the programmer full control if they want it
- Don’t sacrifice performance except as a last resort
- Enforce safety at compile time whenever possible
![Page 62: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/62.jpg)
Languages that really use optionals monads- Rust 🥰😍
Systems language that guarantees memory and thread
safety
- Swift
Apple’s language, made especially for app development
- JavaScript
Everyone’s favorite
![Page 63: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/63.jpg)
Type safety still matters in C++!
![Page 64: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/64.jpg)
A sneaky example of type safety...valueType& vector<valueType>::at(size_t index){
if(index > size()){throw std::out_of_range;
}return *(begin() + index);
}
![Page 65: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/65.jpg)
More bad code
- What if there is no ‘a’ in str?
- No reason str.find shouldn’t return an optional (IMO)
void removeFirstA(string& str){int index = str.find(‘a’);//do something with index
}
![Page 66: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/66.jpg)
Classes with an emphasis on safety- CS110L - Safety in Systems Programming
- Companion course to 110, whenever you take it!
- Systems...but in Rust
- CS242
- Take at least 107 first!
- Learn a lot of languages
- Emphasis on Rust
![Page 67: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/67.jpg)
Recap: Type Safety and std::optional- You can guarantee the behavior of your programs by using a strict type
system!
- std::optional is a tool that could make this happen: you can return either a
value or nothing
- .has_value()
- .value_or()
- .value()
- This can be unwieldy and slow, so cpp doesn’t use optionals in most stl data
structures
- Many languages, however, do!
- The ball is in your court!
![Page 68: Type Safety and std::optional](https://reader034.vdocuments.us/reader034/viewer/2022042713/626707cb9beb2301ac6502b7/html5/thumbnails/68.jpg)
“Well typed programs cannot go wrong.”
- Robert Milner (very important and good CS dude)