Wording tweaks

case-study-borrow-checker
Bradlee Speice 2019-02-04 00:12:01 -05:00
parent ac1d473ac2
commit f7a5fea93d
No known key found for this signature in database
GPG Key ID: 48BEA6257238E620
4 changed files with 21 additions and 17 deletions

View File

@ -75,16 +75,20 @@ we'll follow this guide:
- Boxed closures (FnBox, others?) are heap allocated
- "Move" semantics don't trigger new allocation; just a change of ownership,
so are incredibly fast
- In examples, is address of data before and after the same?
- Can `Copy` trigger allocation?
- Stack-based alternatives to standard library types should be preferred (spin, parking_lot)
## Smart pointers
# Smart pointers
The first thing to note are the "smart pointer" types.
When you have data that must outlive the scope in which it is declared,
or your data is of unknown or dynamic size, you'll make use of these types.
The term [smart pointer](https://en.wikipedia.org/wiki/Smart_pointer)
comes from C++, and is used to describe objects that are responsible for managing
comes from C++, and while it's closely linked to a general design pattern of
["Resource Acquisition Is Initialization"](https://en.cppreference.com/w/cpp/language/raii),
we'll use it here specifically to describe objects that are responsible for managing
ownership of data allocated on the heap. The smart pointers available in the `alloc`
crate should look mostly familiar:
- [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html)
@ -97,10 +101,10 @@ though more than can be covered in this article. Some examples:
- [`RwLock`](https://doc.rust-lang.org/std/sync/struct.RwLock.html)
- [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)
Finally, there is one [gotcha](https://www.merriam-webster.com/dictionary/gotcha):
Finally, there is one ["gotcha"](https://www.merriam-webster.com/dictionary/gotcha):
cell types (like [`RefCell`](https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html))
look and behave like smart pointers, but don't actually require heap allocation.
Check out the [`core::cell` docs](https://doc.rust-lang.org/stable/core/cell/index.html)
follow the RAII pattern, but don't involve heap allocation. Check out the
[`core::cell` docs](https://doc.rust-lang.org/stable/core/cell/index.html)
for more information.
When a smart pointer is created, the data it is given is placed in heap memory and
@ -138,7 +142,7 @@ pub fn my_cow() {
```
-- [Compiler Explorer](https://godbolt.org/z/SaDpWg)
## Collections
# Collections
Collections types use heap memory because they have dynamic size; they will request more memory
[when needed](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve),

View File

@ -30,7 +30,7 @@ we're just focused on interesting things the Rust language can do.
The guiding principal as we move forward is this: *optimizing compilers
won't produce worse assembly than we started with.* There won't be any
situations where stack allocations get moved to heap allocations.
There will, however, be an opera of optimization.
There will, however, be an opera of optimization.
# The Case of the Disappearing Box

View File

@ -99,7 +99,7 @@ With all that in mind, let's talk about situations in which we're guaranteed to
- Closures capture their arguments on the stack
- Generics will use stack allocation, even with dynamic dispatch.
## Structs
# Structs
The simplest case comes first. When creating vanilla `struct` objects, we use stack memory
to hold their contents:
@ -132,7 +132,7 @@ pub fn make_line() {
Note that while some extra-fancy instructions are used for memory manipulation in the assembly,
the `sub rsp, 64` instruction indicates we're still working with the stack.
## Function arguments
# Function arguments
Have you ever wondered how functions communicate with each other? Like, once the variables are
given to you, everything's fine. But how do you "give" those variables to another function?
@ -237,7 +237,7 @@ and passing by reference (either moving ownership or passing a pointer) may have
[slightly different layouts in assembly](https://godbolt.org/z/sKi_kl), but will
still use either stack memory or CPU registers.
## Enums
# Enums
If you've ever worried that wrapping your types in
[`Option`](https://doc.rust-lang.org/stable/core/option/enum.Option.html) or
@ -275,7 +275,7 @@ in assembly, so I'll instead point you to the
[`core::mem::size_of`](https://doc.rust-lang.org/stable/core/mem/fn.size_of.html#size-of-enums)
documentation.
## Arrays
# Arrays
The array type is guaranteed to be stack allocated, which is why the array size must
be declared. Interestingly enough, this can be used to cause safe Rust programs to crash:
@ -320,7 +320,7 @@ There aren't any security implications of this (no memory corruption occurs),
but it's good to note that the Rust compiler won't move arrays into heap memory
even if they can be reasonably expected to overflow the stack.
## Closures
# Closures
Rules for how anonymous functions capture their arguments are typically language-specific.
In Java, [Lambda Expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
@ -387,7 +387,7 @@ pub fn complex() {
In every circumstance though, the compiler ensured that no heap allocations were necessary.
## Generics
# Generics
Traits in Rust come in two broad forms: static dispatch (monomorphization, `impl Trait`)
and dynamic dispatch (trait objects, `dyn Trait`). While dynamic dispatch is often
@ -444,5 +444,5 @@ pub fn do_call() {
```
-- [Compiler Explorer](https://godbolt.org/z/u_yguS)
It's hard to imagine practical situations where dynamic dispatch
would be used for objects that aren't heap allocated, but it can be done.
It's hard to imagine practical situations where dynamic dispatch would be
used for objects that aren't heap allocated, but it technically can be done.

View File

@ -16,7 +16,7 @@ we'll go into below. The
[full specification](https://github.com/rust-lang/rfcs/blob/master/text/0246-const-vs-static.md)
for these two memory types is available, but we'll take a hands-on approach to the topic.
## **const**
# **const**
The quick summary is this: `const` declares a read-only block of memory that is loaded
as part of your program binary (during the call to [exec(3)](https://linux.die.net/man/3/exec)).
@ -144,7 +144,7 @@ but the specifications are clear enough: *don't rely on pointers to `const`
values being consistent*. To be frank, caring about locations for `const` values
is almost certainly a code smell.
## **static**
# **static**
Static variables are related to `const` variables, but take a slightly different approach.
When the compiler can guarantee that a *reference* is fixed for the life of a program,