![](/static/253f0d9b/assets/icons/icon-96x96.png)
![](https://lemmy.ml/pictrs/image/b5ded61a-ac07-413b-a2bc-3d7321eadde2.jpeg)
I’m sure there are a bunch of patterns that emerge out of this (anyone with some wisdom here?) …
The classical one is something that looks like the following:
struct LoggedOut;
struct User {name: String};
struct Admin {name: String};
impl LoggedOut {
fn login(self, name: String, password: String) -> User {
User { name }
}
fn admin_login(self, name: String) -> Admin {
Admin { name }
}
}
impl User {
fn log_out(self) -> LoggedOut {
LoggedOut {}
}
}
impl Admin {
fn log_out(self) -> LoggedOut {
LoggedOut {}
}
}
fn fetch_user_preferences(user: User) { /*...*/ }
fn do_admin_action(admin_account: Admin) { /* ... */ }
fn main() {
let mut user_session = LoggedOut {};
/* (get user input) */
match input {
"login" => {
user_session = user_session.login(name, password);
}
"admin" => {
user_session = user_session.admin_login(name);
}
}
}
This would prevent you from writing code that uses the user’s info / session “object” after they have logged out (and/or before they have logged in). On its own it’s naive and a bit encumbering - I expect an enum would make more sense but then you can’t restrict via types which user session values can and can’t be passed to specific functions. In any case, when you are building a whole system around it it can be very useful to have the compiler enforcing these sorts of things “in the background”.
This is basically what Gary Bernhardt is talking about in the talk you linked.
An important part of that process that needs mentioning is that when the mothers are convinced by Nestle to feed their babies formula instead of their breast milk, their bodies will stop producing the milk before the baby is weaned from it.
So Nestle literally endangers babies’ lives just to sell more baby formula.