-
Notifications
You must be signed in to change notification settings - Fork 1.9k
"borrow checker invariants" section of the "leveraging the type system" chapter #2867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
"borrow checker invariants" section of the "leveraging the type system" chapter #2867
Conversation
…n to lifetime connections
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/single-use-values.md
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/aliasing-xor-mutability.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/aliasing-xor-mutability.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/aliasing-xor-mutability.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/aliasing-xor-mutability.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/lifetime-connections.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/lifetime-connections.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/lifetime-connections.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/lifetime-connections.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize for the enormous delay here -- it's been a busy couple of months!
This looks great, and I appreciate seeing previous comments included here.
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/lifetime-connections.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass, generally looking good, but I left some comments that may lead to structural changes, so I expect to do another detailed pass after you land some changes.
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants.md
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,80 @@ | |||
--- | |||
minutes: 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the timing information.
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/single-use-values.md
Outdated
Show resolved
Hide resolved
|
||
- By keeping constructors private and not implementing clone/copy for a type, | ||
making the interior type opaque (as per the newtype pattern), we can prevent | ||
multiple uses of the same, API-controlled value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not clear what "API-controlled" means here.
do_something_with_transaction(transaction); | ||
let assumed_the_transactions_happened_immediately = db.results(); // ❌🔨 | ||
do_something_with_transaction(transaction); | ||
// Works, as the lifetime of "transaction" as a reference ended above. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be misunderstanding your intent behind this example, but it does not feel realistic realistic because the database didn't get a notification that the borrow has ended, and thus could not have started executing it. In other words, it is not clear what the DatabaseConnection type achieved by being locked out while the transaction was borrowed out.
Maybe you can fix it by wrapping the reference in a custom wrapper type which implements Drop? Ideally, that drop() would also print a message (like "executing query...") to make it clear to the audience that the database can indeed fill in the result list.
|
||
# Lifetime "Connections" & External Resources | ||
|
||
Using `PhantomData` in conjunction with lifetimes lets us say "this value may |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This made me think, do we have a slide on PhantomData, just about the concept by itself? Should we have one?
It seems like there are a few things to say to motivate PhantomData's existence (that is, before we even introduce it on the slide), in particular that the compiler infers certain properties of a user-defined type based on its fields - this would be surprising to many people, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not. Prior to starting work on this chapter there wasn't a mention of PhantomData in the repository at all.
If there's a place for it to exist, it's likely in a revision on the typestate work. I'll pull together something short that can slot in just before the lifetime-connections slide for now under the assumption it can be moved about as needed.
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/aliasing-xor-mutability.md
Outdated
Show resolved
Hide resolved
src/idiomatic/leveraging-the-type-system/borrow-checker-invariants/generalizing-ownership.md
Outdated
Show resolved
Hide resolved
majority of them. See: | ||
[Lifetime Elision](../../../lifetimes/lifetime-elision.md). | ||
|
||
</details> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This slide might be a place where an analogy might help some listeners understand what we are trying to get at when we say that the borrow checker and lifetimes are just another API design tool. Here's one possible analogy. WDYT?
Generics in Java were added primarily to support type-safe collections. In fact, Java 5 added generic type arguments to existing standard library collection types that were previously non-generic! So the language designers had a clear primary use case in mind. However, generics turned out to be useful in many other API designs. So it would be too narrow-minded to present Java generics as "a language feature for type-safe collections."
Similarly, the lifetimes and the borrow checker were introduced in Rust for compile-time memory safety guarantees, but their applicability in API design is broader. We (the Rust community) are still discovering design patterns and trying to understand what these tools can do for API design beyond memory safety.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good thing to bring up, I'll pull together some references to drop in. If you've got suggestions on pieces covering this I'd be happy to hear about them, but I understand linkrot and the ephemeral nature of back-channel discussion of the time may have gotten to most of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSR 14 which introduced generics lists only one goal specific to a use case, and it is "Good collections support. The core Collections APIs and similar APIs are perhaps the most important customers of genericity, so it is essential that they work well as, and with, generic classes." Furthermore, this is the #1 goal of the proposal overall.
An empirical research article that I could find, Java generics adoption: how new features are introduced, championed, or ignored studies how generics were adopted in practice. It includes a data-driven argument that the most common parameterized types are collections (the only non-collection-related type in Table 1 is Class<?>
). This aligns with my intuition: the primary use case is collections, but there are other cases where generics turned out to be useful (for example, Class<?>
in the standard library, TypeToken<?>
in Google's Guava to work around type erasure in Java's generics, or the "recursive generics" pattern similar to CRTP in C++).
One source that I had high hopes for, ACM's History of programming languages journal, unfortunately does have a piece on Java.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wonderful, thank you!
Co-authored-by: Dmitri Gribenko <[email protected]>
&self.query_results | ||
} | ||
pub fn commit(&mut self) { | ||
/* Work omitted, including sending/clearing the transaction */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* Work omitted, including sending/clearing the transaction */ | |
// Work omitted, including sending/clearing the transaction |
```rust,editable | ||
mod cryptography { | ||
pub struct Key(/* specifics omitted */); | ||
// Pretend this is a cryptographically sound, single-use number. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Pretend this is a cryptographically sound, single-use number. | |
// A single-use number suitable for cryptographic purposes. |
pub struct Key(/* specifics omitted */); | ||
// Pretend this is a cryptographically sound, single-use number. | ||
pub struct Nonce(u32); | ||
// And pretend this is cryptographically sound random generator function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// And pretend this is cryptographically sound random generator function. | |
// A cryptographically sound random generator function. |
pub struct Nonce(u32); | ||
// And pretend this is cryptographically sound random generator function. | ||
pub fn new_nonce() -> Nonce { | ||
Nonce(std::time::UNIX_EPOCH.elapsed().unwrap_or_default().subsec_nanos()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nonce(std::time::UNIX_EPOCH.elapsed().unwrap_or_default().subsec_nanos()) | |
Nonce(4) // chosen by a fair dice roll, https://xkcd.com/221/ |
The timestamp was not a good RNG anyway, and showing a good one is not the point of the example. With a bit of lighthearted humor we can telegraph that this is a pretend-RNG.
Nonce(std::time::UNIX_EPOCH.elapsed().unwrap_or_default().subsec_nanos()) | ||
} | ||
|
||
// We consume a nonce, but not the key or the data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// We consume a nonce, but not the key or the data. | |
// Consume a nonce, but not the key or the data. |
} | ||
|
||
use cryptography::*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
use cryptography::*; |
- When a new feature is introduced to users, it is often done so with a specific | ||
idea of what it will be used for. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- When a new feature is introduced to users, it is often done so with a specific | |
idea of what it will be used for. | |
- Language features are often introduced for a specific purpose. |
not been foreseen. | ||
|
||
In 2004, Java 5 introduced Generics with the | ||
[main stated purpose of enabling type safe collections](https://jcp.org/en/jsr/detail?id=14). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[main stated purpose of enabling type safe collections](https://jcp.org/en/jsr/detail?id=14). | |
[main stated purpose of enabling type-safe collections](https://jcp.org/en/jsr/detail?id=14). |
[main stated purpose of enabling type safe collections](https://jcp.org/en/jsr/detail?id=14). | ||
|
||
Since then, users and developers of the language expanded the use of generics | ||
to other areas of type safe API design. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to other areas of type safe API design. | |
to other areas of type-safe API design. |
What we aim to do here is similar: The borrow checker, after being introduced | ||
to people with the purpose of avoiding use-after-free and data races, is being | ||
used to model things that have nothing to do with preventing those classes of | ||
misuse. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What we aim to do here is similar: The borrow checker, after being introduced | |
to people with the purpose of avoiding use-after-free and data races, is being | |
used to model things that have nothing to do with preventing those classes of | |
misuse. | |
What we aim to do here is similar: Even though the borrow checker was introduced | |
to prevent use-after-free and data races, it is just another API design tool. It can be | |
used to model program properties that have nothing to do with preventing memory safety bugs. |
exclusive reference we prevent access to the other fields of that struct under | ||
a shared / non-exclusive reference until the lifetime of that borrow ends. | ||
|
||
Note: This has to be via a method, as the compiler can reason about borrowing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This has to be via a method, as the compiler can reason about borrowing | |
- The `transaction` field must be borrowed via a method, as the compiler can reason about borrowing |
This is a major part (esp. since now there's a demonstration), so it deserves a top-level bullet point.
Adds materials on the "leveraging the type system/borrow checker invariants" subject.
I'm still calibrating what's expected subject-and-style wise, so do spell out things where I've drifted off mark.