Rust Book
Overview
Various notes and thoughts regarding the Rust Book.
Chapter 1: How to install rust
I was pleasantly surprised that I could get things working on Alpine without too much issue.
Chapter 2: hands-on intro to rust
I intially skipped this, then went back just to get used to building projects with cargo.
Chapter 3: Rust features similar to other languages
Yeah, this mostly felt familiar.
Chapter 4: Ownership
I thought this was introduced pretty well. I have a feeling that this will get tricky quickly in practice though. Already it is having me re-think how I'd port some of the functionality of graforge to Rust.
Chapter 5: Structs and Methods
Reasonably familiar C-ish concepts.
Chapter 6: Enums, Match, etc
This kind of looks like a case switch if you squint. I've had experience with pattern matching from FAUST, which I believe is where it is heading. Will be interested to see what that looks like.
Overall, I feel like this is more powerful than it looks.
Chapter 7: Modules
Packages, Crates, and Modules. Relative and absolute paths.
The use
statement. Private vs Public code.
Chapter 8: Common Collection Data Structures
A jumble of common data structs.
Vectors: creating, updating, out-of-scope/dropping, reading, iterating, using an enum to store multiple types in a vector.
Strings: these are challenging for newcomers to grok! Many different types of strings.
Hashmaps: kind of what you'd expect. Rust uses a hash algorithm by default that is a trades performance for security (SipHash).
Chapter 9: Error Handling
Recoverable and unrecoverable.
Panic backtraces. Recoverable errors using the Result
type.
Using the match
operator to match errors. unwrap
and
expect
. Error propagation, with an example
starting verbosely with match and adding syntactic sugar
to make things clearer. Introduction to the ?
operator.
Best practices for when to panic or not to panic. Creating
custom types for validation.
Chapter 10: Generics, Traits, and Lifetimes
This is a very meaty chapter! generic type parameters (apply code to different types), traits and trait bounds (even though types are generic, ensure that they'll have the correct behavior the code needs), and generic lifetime parameters (ensures that code won't have dangling references).
Generics: the one feature everybody loves to talk about Go not having.
Generics in: Structs, Enums, Method definitions. The way generics are mixed up in 10-11 is kind of confusing to me.
Generics do not add any additional overhead (but I bet the compile time gets a penalty). Some explanation for how this works.
Traits: kind of like interfaces in other languages (makes me think of Go? Been a while since I wrote any Go.)
Using tweets vs news article summaries as an example. Default implementations. Traits as parameters.
Trait bounds, and trait bounds syntax. Using trait bounds to conditionally implement methods.
Lifetimes: the scope for which a reference is valid.
Dangling references, Borrow Checker, Generic lifetimes in functions, Lifetime annotation syntax, annotations in function signatures, thinking in terms of lifetimes, lifetime elision, annotations in method defintions, static lifetimes.
Chapter 11: Testing
AKA writing Automated Tests. How to write tests. The anatomy of a test function. The assert macros, assert_eq! and assert_neq!. Custom failure messages. Panic checks. Using Result. Parallel vs consecutive tests. Showing function output. Running tests by name (partial matches run can run multiple tests). Tests that are usually ignored.
Test Organization. Unit tests. Integration tests.
Chapter 12: Implementing A Toy Grep
Minigrep, etc.
Chapter 13: Closures and Iterators
Closures: a function-like construct you can store in a variable.
Iterator: a way of processing a series of elements.
First introduces closure through refactoring a fictional code for a workout app. Functions, to closures, to closures with cached parameters. Narrow scoped closure means compiler can infer a lot of things (no type annotations required usually). Closure notation. Lazy evaluation, function types. Different ways of capturing environment with closures: FnOnce, FnMut, Fn.
Iterators are lazy, and won't do anything if it doesn't have to. Iterators is a trait in Rust, that has at least one method called "next". "Consume the iterator": or using up the iterator. Other iterator methods like "map". Closures that capture environment. Custom Iterator traits.
Minigrep from previous chapter is refactored to use closures/iterators.
Performance test: loops vs iterators. Iterators win the benchmark! Iterators are zero-cost abstractions.
Audio Decoder! Looks like some kind of LPC. Efficient high level abstractions for otherwise low-level code.
Chapter 14: Cargo In-Depth
Release profiles. Crates.io, and how to publish there. special comments for documentation, testing inline examples in comments. pub use for exporting convenient API. Settingup crates.io account and getting ready to publish... once it's up there, it's up there. Using yank to remove (disable?) versions in crates.io. Cargo workspaces. Installing binaries with "cargo install".
Chapter 15: Smart Pointers
Smart Pointers: pointers with extra capabilities.
This chapter was quite challenging to read through! I actually typed out and ran some of the example programs in this chapter.
Most common smart pointers:
Box: the most basic smart pointer for heap allocation.
Rc: Reference counting (enables multiple ownership).
Ref and RefMut (via RefCell): runtime borrowing instead of compile-time borrowing.
Box types enable recursive types
, suchs as the Cons
list (linked list I guess?) from LISP. Recursive types,
size can't be known.
Dereference operator using the deref
trait. Makes
smart pointers act like regular references. deref
traits can be implemented on user-defined types.
Deref coercion: basically syntactic sugar that works with stuff using deref.
DerefMut is Deref on mutable references. Mutable can always go to immutable, not the other way around.
Drop Trait: basically destructor. Can be explicitely
called with std::mem::drop
.
Rc only works for multiple immutable references. To be mutable, use RefCell.
Interior Mutability: design pattern that allows mutability even when there are mutable references to that data.
RefCell checks borrowing rules at runtime, which means there is a possibility that a program could panic.
Memory Safety does not prevent memory leaks. Reference Cycles (cyclical references?) can cause leaks. This is demonstrated with the Cons list used in this chapter.
Weak counting is a way to prevent reference cycles.
The strong count and weak count of a value can be
explicitly retrieved with weak_count
and strong_count
functions.
upgrade
converts a weak pointer to a reference that
can be used (it can be None too). downgrade
will take
a reference and convert it to a weak pointer.
Chapter 16: Different Models of Concurrency
Fearless concurrency! std::thread
thread::spawn
creates a new thread and saves the handle.
handle.join()
joins the threads.
The move keyword: transfers ownership of values that a closure in a thread uses. Otherwise it's a Rust error.
Message passing via channels. Rubber duckies down the
river. mpsc
is multiple producer, single consumer.
Sending values over channels transfers ownership.
When there are multiple values/producers, using an iterator
abstracts away the need to call recv
, and will stop
iterating when the channel has closed. Producers across
multiple threads will cause the order of values received
to vary.
Shared-state concurrency. "do not communicate by sharing memory. share memory by communicating".
Mutex, or mutual exclusion, allow access to data one thread at a time.
The Mutex type in Rust is a smart pointer. MutexGuard
gets returned with a call lock
, and the reference
is then returned with unwrap
.
When using multiple threads, ownership can't be
moved between them with lock
. multiple-ownership must be
used.
Rc (typically used for multiple-ownership scenarios) is not thread-safe. So something else must be used...
The send
marker trait is one that indicates ownership
can be transferred between threads. Most types in Rust
are Send, with the exception of Rc.
The sync
marker trait indicates that a value can
be referenced from other threads. Rc, RefCell, and Cell
in general do not have Sync.
Manually implementing sync/send traits involves implementing unsafe Rust code.
Chapter 17: Object Oriented Programming
OOP means a lot of things to a lot of different people. Does Rust meet the requirements of OOP?
Encapsulation, or the ability to make data not direct accessible, is an OOP thing. Rust can do it using structs and methods.
Inheritance, the ability for an object to take on a parent objects data and behavior, is not a thing in Rust.
Polymorphism, the ability to substitute multiple objects at runtime if they share certain characteristics, is possible with traits.
How do we work with a list of things where the types aren't all known? Trait Objects.
Being concerned only with the messages a value responds
to rather than the values concrete type is similar
to the concept known as duck typing
.
Trait objects use dynamic dispatch. Dynamic dispatch adds some runtime cost, but adds flexibility.
Object safety: there are many complex rules to object safety, but the gist is: the return type can't be self, and that there are no generic type parameters.
Sample code: building a blog post generator using the Object State design pattern.
Take this sample code, and rework it to make it less OOP-y and more Rust-y, using types instead of encapsulation in the state. These new changes cause compiler errors to happen when content is requested before it is published, rather than just returning empty strings like before.
Chapter 18: Patterns and Pattern Matching
Patterns are a special syntax in Rust for matching against structure types.
match arms: constists of match
, a value to match on,
then one or more "arms" consisting of a pattern and
something to run if the value matches.
Match must be exhaustive: every possibility must be
accounted for. Common approach to this is to have
the last arm be a catch-all using _
.
Combinations of if let
and else
allow for more
flexible pattern matching than match
. Watch for
shadowing! Also, the compiler will not check for
exhaustiveness.
while let
lets a while loop run as long as a pattern
continues to match.
In a for
loop, the pattern is the value that directly
follows the for keyword. In for x in y
the x
is
the pattern.
A let
statement is actually a pattern! It follows
the syntax "let pattern = expression"
Function parameters can also be patterns.
Irrefutable patterns mean that a pattern can match for any possible value. Refutable patterns mean that some possible values won't match.
let
requires irrefutable patterns, so refutable
patterns like like Some(x)
won't work.
if let
takes in refutable patterns. if a pattern
doesn't match, the code in curly brackets won't
get run. Note that irrefutable patterns will trigger
a warning from Rust (the if-let is probably not necessary).
You can match patterns against literals using match
.
When matching named variables, match
will create a new
scope and shadow variables with the same name.
Using |
in match expressions will match multiple patterns
for one arm.
Using "..=" allows use of range in match expressions. Only works on numbers or chars.
One can destructure structs, enums, tuples, and references to use different parts of these values.
Nested structs/enums can also be matched too.
The _
can be used to ignore entire values. Parts of
values too when it is nested.
Starting a variable with _
, such as _x
, will tell the
compiler to ignore it if is being unused. The binding
still happens, Rust just won't say anything. _
by itself
will not do binding.
Remaining parts of values can be ignored using ..
. Using
..
must always be unambiguous.
Match guards: more or less conditionals after a pattern
in a match
arm.
Operator precedents: the |
operator gets evaluated
before match guards. In other words 4 | 5 | 6 if y
is
equivalent to (4 | 5 | 6) if y
.
Using the @
operator can bind a value in a pattern
while also testing it. Using @
tests a value and save
it in a variable with one pattern.
Chapter 19: Advanced Topics
These are topics you'll occasionally run into in the wild, and useful in very specific situations.
Topics: unsafe Rust, advanced traits, advanced types, advanced functions, and macros.
Unsafe Rust: rust that does not enforce memory safety.
Why unsafe? Rust compiler is conservative, can reject valid programs. Underlying computer hardware is inherently unsafe, and Rust is designed to be a systems language.
Unsafe block starts with the unsafe
keyword. Grants
unsafe superpowers
: dereference a raw pointer, call
an unsafe function or method, access or modify mutable static
variable, implement unsafe trait, access fields of
unions.
Raw pointers: similar to references, written as
*const T
(immutable)
and *mut T
(mutable). Immutable raw pointers can't
be assigned after being dereferenced.
Raw pointers ignore borrowing rules, have no guarantee of pointing to valid memory, can be null, and don't implement any automatic cleanup.
One major use-case for raw poitners is interfacing with C code. Another is building safe abstractions that the compiler doesn't understand.
Unsafe functions look like regular functions, just with an unsafe added to it. Using an unsafe function means you've taken full responsibility for making sure it behaves correctly.
Calling unsafe blocks inside of a safe function is a common
abstraction. Ex: split_at_mut
, which splits up a mutable
vector into two parts. The Rust compiler isn't smart
enough to understand that this is safe, so part
of the operation is done inside unsafe
.
extern
is used to create and use the Foreign Function
Interface (FFI). It can do things like call C code.
extern
can also be used to call Rust code from C. The
no_mangle
annotation has to be turned on to keep the
naming consistent.
Global variables in Rust are known as static
variables.
They are similar to constants, but they have a fixed
address in memory, and can be mutable.
Static values can only store references with the 'static lifetime.
A trait is considered unsafe when at least one of its methods has some invariant that the compiler can't verify.
Unions in Rust are primarily used to interact with C code. They are inherently unsafe because Rust can't guarantee the type of one at any given time.
Associated types: a "placeholder" used in traits that gets "filled in" later. Similar to generics. Except with generics, a trait for a particular type can be implemented multiple times.
In generics, there can be default "concrete" types. A type doesn't need to be explicitely defined if the default works.
Operator overloading in Rust: doesn't allow to make new
operators, but it does allow overloading the existing
operators and corresponding traits in std::ops
.
If traits being implemented share methods with the same name, one may have to explicitely distinguish which method you are talking about. If the type itself has a method with that name, it will call that one by default.
For method name ambiguities in associated functions, Fully Qualified Syntax is utilized.
Supertrait: used to require one traits functionality within another trait.
Newtype: pattern that implements external traits on external types. Normally this wouldn't be doable because of the orphan rule.
Orphan Rule: traits can be implemented on a type as long as either the trait or the type are local to the crate.
Newtype inolves creating a new type in a tuple struct, which acts as a thin wrapper around the type we want to implement.
Type alias: gives an existing type a new name. Creates a synonym.
The !
operator is known as the empty type
or
never type
. It's the return type of a function that
will never return, which are referred to
as diverging functions
.
Dynamially sized types, or DSTsx, or unsized types, are types whose size can only be known at runtime.
Function pointers: allow regular functions to be passed
as arguments using the fn
type. Function pointers can
always be passed off in places that expect closures.
Returning a Closure? This chapter shows you how!
Macros: used for metaprogramming
in Rust, or writing
code that writes code.
Declarative Macros: most widely used form of macro. Very
similar conceptually to match
. Implemented using
macro_rules!
, but this may be eventually be deprecated
in favor of something else that addresses the weird edge
cases.
Procedural macros: macros that act more like functions. Take some code as input, operate on that code, and produce some code as output. Implementing these currently have a lot of weird technical restrictions, which may change in the future.
Derive macros are ???.
Attribute-like macros: like derive macros, but instead of generating code for the derive attribute, they allow you to create new attributes.
Funtion-like macros: macros that look like functions.
similar to declative macros. these take a TokenStream
parameter and then manipulate it using Rust code.
Chapter 20: A multi-threaded webserver
This was basically a tutorial that managed to cover a lot of topics encountered in the previous chapters.
Messages
Any messages tagged with the group rustbook
.
[0a4a708e] 2022-03-28-13-10: completed final chapter.
[e2fbc0b9] 2022-03-27-09-26: I just hobbled through the advanced chapter. Now onto the final chapter! huzzah!
[21d5bb17] 2022-03-27-09-21: oops, I missed something about derive macros
[ee14f391] 2022-03-27-09-19: procedural macros come with a mini-tutorial. skimming, may return back to this if I need to use procedural macros.
[160060bc] 2022-03-27-09-13: macros section seems to be the at the fringes of Rust. Lots of language like "may be deprecated later" and "we hope to eliminate in the future".
[e6ad3452] 2022-03-27-09-01: metacode: code that writes other code.
[24d57e41] 2022-03-27-07-24: my initial impression of type aliasing in rust is that it's similar to typedef in C. But I'm sure there's a little more to it.
[22a59432] 2022-03-27-07-20: this advanced features chapter did say in the beginning that it is more of a reference chapter. The writing would certainly seem like it, because there are far more references to previous chapters here.
[e6683ca4] 2022-03-27-07-16: orphan rule: in Rust, a rule that states that a trait can be implemented on a type as long as either the trait or the type are local to the crate.
[9e58b0c2] 2022-03-27-07-10: I have no recollection of the orphan rule.
[a02386de] 2022-03-27-07-06: supertraits are confusing.
[368b16d7] 2022-03-26-19-13: If there's ambiguity with method names and traits, and the type has a method with that name, it will call that one by default. But what happens when there isn't method with that name in the type? Is that a compiler error?
[97f024eb] 2022-03-26-19-03: default concrete types. is "concrete" a special term?
[3c1c4235] 2022-03-26-19-01: in generics, the types must be annotated in each implementation.
[13a1e1b9] 2022-03-26-19-00: the big difference seems to be that with generics, an interface with a certain type can be implemented multiple times.
[e71693e8] 2022-03-26-18-57: lol. next paragraph addresses when to use associated types vs generics. okay. I'm glad I'm asking appropriate questions.
[74aaa029] 2022-03-26-18-56: associated types, from what I can understand so far, sound a bit like generics because they both have the concept of a placeholder that gets "filled in" later on.
[f46b2864] 2022-03-26-18-43: Foreign Function Interface (FFI): a way for a programming language to define functions and enable different (foreign) programming languages to call those functions.
[f0f2e87f] 2022-03-26-05-46: unsafe superpowers: possible actions in unsafe Rust. Dereferencing a raw pointer, calling an unsafe functin, Access/modify a mutable static variable, implement an unsafe trait, and access fields of unions.
[8490025e] 2022-03-25-10-54: match guard: an additional if condition specified after the pattern in a match arm that must also match, along with the pattern matching, for that arm to be chosen.
[847daf00] 2022-03-25-09-14: refutable: in the context of Rust pattern matching, refers to patterns that can fail to match for some possible value.
[445dbdf9] 2022-03-25-09-13: irrefutable: in Rust, this refers to patterns that will match for any possible value passed.
[07e6e416] 2022-03-25-06-10: the while let structure is interesting. instead of a condition like in C, it's a pattern.
[570b1a82] 2022-03-25-06-02: exhaustive: in the context of rust pattern matching, meaning every possibility must be accounted for.
[24ce6f4c] 2022-03-24-06-39: OOP chapter done. now on to patterns.
[e542fea6] 2022-03-24-06-18: Took me a moment to understand what the state pattern was doing in the Rust code. Regular old state variables are just data, like a flag you set. Things read the flag and change. In this example, the state is an object, which means the state actually does stuff via methods. When the state changes, the stuff it does changes as well.
[cb0d7642] 2022-03-24-06-02: I'm also going to need to grok what Some
does.
[211a8266] 2022-03-24-06-00: was the take
method discussed in a previous chapter?
[dcf99dd6] 2022-03-24-05-56: Rust doesn't allow for unpopulated fields.
[3f1e4d71] 2022-03-24-05-43: state pattern: object oriented design pattern, where a value has some internal state, represented by state objects
, and the value's behavior changes based on the internal state.
[1831cfda] 2022-03-23-09-00: I'd probably want to look into FAUST generated rust code and see what they do. Chances are, they made good design decisions.
[09a5c8db] 2022-03-23-08-59: how expensive is dynamic dispatch in Rust? would it be negligible for realtime audio?
[3b7237fd] 2022-03-23-08-57: trait objects use dynamic dispatch. it works by using pointers inside the trait object to know which method to call. there is a runtime cost with this lookup that occurs as a result of this.
[9875fa4e] 2022-03-23-08-55: code that results from monomorphization is doing static dispatch
[12fbc7f1] 2022-03-23-08-55: dynamic dispatch: when the compiler can't tell at compile time which method is being called.
[0842979e] 2022-03-23-08-54: static dispatch: when the compiler knows what method you are calling at compile-time.
[341c1d58] 2022-03-23-08-49: duck typing: a concept in dynamically typed languages. If it walks like a duck and quacks like a duck, then it must be a duck!
[59699e82] 2022-03-23-06-19: trait object: mechanism that points to both an instance of a type implementing a specified trait, as well as a table used to look up trait methods on that type at runtime.
[b59b86a9] 2022-03-23-06-17: ooh the book is describing a pattern I need for my audio stuff to work: have a list of things where the types aren't known.
[85f436a6] 2022-03-23-06-12: this OOP chapter has a lot of kind-of-but-not-really bits in it.
[dc34daaa] 2022-03-23-06-10: bounded parametric polymorphism: a type of polymorphism that abstracts over different possible types and trait bounds to impose constraints on what those types must provide.
[a0aee11f] 2022-03-23-06-08: polymorphism: the ability to substitute multiple objects for eachother at runtime if they share certain characteristics.
[5df61514] 2022-03-23-06-04: inheritance: a mechanism whereby an object can inherit from another object's definition, thus gaining the parents object data and behavior without having to define them again.
[f11b1945] 2022-03-23-05-58: encapsulation: implementation details of an object aren't accessible to code using that object.
[70e416d1] 2022-03-23-05-56: seems like there's some general discussion on OOP in general. History, concept, etc. Maybe more so than other chapters? Concurrency also did this a little bit.
[e79e5613] 2022-03-23-05-53: onto object oriented programming
[da0d2f71] 2022-03-23-05-53: done with the concurrency chapter! no need to backtrack for the (rustbook) page, since I decided to read-and-summarize in chunks.
[968fd317] 2022-03-23-05-45: sync/send: two concurrency traits that are embedded in the language./
[32143a22] 2022-03-23-05-45: most concurrency features are part of the standard library, not the language itself.
[39b71fdf] 2022-03-22-09-24: Mutex, like the Cell family of types, uses interior mutability. That's how the counter in this example was able to be changed.
[73d8b2e8] 2022-03-22-09-23: atomics aren't the default because they impose a performance penalty
[7272b373] 2022-03-22-09-22: The Arc is similar to the Rc type, but it's atomic so it can be used in multithreaded scenarios. In other words, Arc is an atomically reference counted type.
[ba5b316d] 2022-03-22-09-21: Rc
[10a3753e] 2022-03-22-06-30: writing the (page) page as I go. no more or minimal backtracking.
[00538a39] 2022-03-22-06-26: apparently "you can't get unlocking and locking wrong" with Rust's ownership rules.
[7027165b] 2022-03-22-06-25: mutex: an abbreviation for mutal exclusion. allows only one thread to access some data at any given time.
[24520f46] 2022-03-22-06-23: "do not communicate by sharing memory. share memory by communicating". this is a go motto, quoted in the rust book.
[6818ea05] 2022-03-22-06-20: multiple producers looks very similar to multiple values. multiple threads spawned, one receiver in an iterator like before. the order varies.
[bba0cade] 2022-03-22-06-18: these values were sent on one thread. I think the idea is that producers work across multiple threads?
[1f3f363f] 2022-03-22-06-17: woops, they actually call these 'values', not 'producers'. getting my semantics wrong.
[207b81b1] 2022-03-22-06-15: It seems like using an iterator abstracts away the need for recv in the context of multiple producers.
[2b23d8e1] 2022-03-22-06-08: I see a recv
. Looks like they are borrowing classic networking C function naming conventions.
[d826c372] 2022-03-22-06-05: multiple producer, single consumer (mpsc): a channel in Rust. It can have multiple sending ends that produce values but only one receiving end that consumes those values.
[851f52bd] 2022-03-22-06-01: channel: a programming concept used to accomplish message-sending concurrency.
[d2e55acb] 2022-03-22-05-57: the move
keyword forces the closure to take ownership of the values it is using.
[cbe06043] 2022-03-22-05-55: so far, it seems all threads in Rust are closures.
[3477e401] 2022-03-22-05-50: calling join on the handle blocks the thread curerntly running until the thread represented by the handle terminates.
[85899c5a] 2022-03-22-05-47: MN Model: A threading model (green threads), where there are M green thread per N operating system threads. M and N are not necessarily the same number.
[50199a21] 2022-03-21-09-43: runtime (rust): code that is included by the language in every binary.
[3afb8826] 2022-03-21-09-42: green thread: threads that are provided by the programming language, rather than through the OS API.
[b4c1d277] 2022-03-21-09-39: fearless concurrency: a core design philosophy of Rust, that emphasizes more compile-time errors of code rather than run-time errors.
[98e7c2a9] 2022-03-21-09-35: Turning concurrency runtime errors into compiler errors was a big part of the original design ethos of Rust.
[cde7896e] 2022-03-21-09-34: parallel programming: programming where different parts of the program execute at the same time.
[4fb9cc3b] 2022-03-21-09-34: concurrent programming: programming where different parts of a program execute independently.
[5216f541] 2022-03-21-09-33: safe concurrency is such a big part of Rust's goals. Concurrency is nearly the polar opposite of what I typically work on and think about, so this will probably be a new headspace for me.
[03fa7b67] 2022-03-21-09-31: onto chapter 16: concurrency
[becf9de7] 2022-03-21-09-02: just finished chapter 15 (smart pointers), now backtracking and writing a blurb in (rustbook).
[689ad393] 2022-03-21-06-03: 'the lack of infinite output indictates that this code didn't create a reference cycle.'
[569e3303] 2022-03-21-05-48: in 15-25, my best guess is the pattern matching syntax is actually the thing declaring the "item" variable. This is binary pattern matching. Something or nothing. I think things would become a bit clearer if I knew what would happen if I tried to add more pattern matching staements to it.
[196246ff] 2022-03-21-05-45: in 15-26: I'm getting tripped up by the let syntax in the if statement. that's still pretty new to me.
[c7842bef] 2022-03-21-05-42: 15-26 and 15-25 both have a lot of implicit stuff happening. in 15-25, I don't know how "item" is conjured from the match statement. in 15-26, I don't know where "link" comes from.
[9e6f08cc] 2022-03-19-10-40: memory safety in rust does not guarantee prevention of memory leaks. reference cycles can leak memory.
[238f19aa] 2022-03-19-10-39: memory leak: a situation where memory is allocated but not cleaned up.
[7403a55a] 2022-03-19-06-34: mock objects: specific types of test doubles that record what happens during a test so you can assert that the correct actions took place.
[ca92867a] 2022-03-19-06-34: test double: a type used in place of another type during testing.
[4bad641c] 2022-03-19-06-21: By default, Rust checks the borrowing rules at compile time, which allows bugs and errors to be caught sooner. Checking borrowing rules at runtime (such as RefCell) will enable certain kinds of memory-safe scenarios. If something goes wrong in the program, it will panic.
[d4d5d479] 2022-03-19-06-16: interior mutability: a design pattern in Rust that allows you to mutate data even when there are immutable references to that data.
[b0fe79fc] 2022-03-19-06-13: Rc::clone() doesn't make a deep copy like regular clone(). It only increases the reference count.
[6881b6f5] 2022-03-19-06-09: realizing that graforge uses reference counting.
[469bd78d] 2022-03-19-06-04: constructor: a function that creates an instance.
[adc76cb5] 2022-03-19-06-03: destructor: a function that cleans up an instance.
[e2405e70] 2022-03-19-05-58: the Drop
trait customizes what happens when a value is about to go out of scope.
[6a5c9992] 2022-03-19-05-56: you can coerce a mutable reference to be an immutable one, but not the other way around.
[c00cbfbc] 2022-03-19-05-51: (maybe I should just finish this section. ha)
[dc4660b9] 2022-03-19-05-51: I seem to understand that deref coercion is a conversion process applied to arguments. "syntactic" sugar, for what otherwise seems to be very messy looking code.
[e3cdb777] 2022-03-19-05-46: trying to grok deref coercion
.
[9a5170a3] 2022-03-19-05-42: without the Deref
trait, the compiler can only dereference &
references.
[8a4fca26] 2022-03-19-05-39: dereference operator: in Rust, this is an operator represented with *
. Implemented the Deref
trait allows you to customize the trait of the derefernce operator.
[83d56902] 2022-03-15-06-29: Boxes seem to be the most 'basic' smart pointer type, compared to the other smart pointer types.
[3d8317af] 2022-03-15-06-23: note to self: chapter says if generics were used, any type could be used. Does that mean they all have to be the same type? Or can there be multiple types? Thinking ahead about my needs for my Rust DSP stuff.
[88bb61d9] 2022-03-15-06-20: recursive types are reminding me of the chicken/egg problems that happen when building linked list structures in C. Looking at the cons structure being defined right now.
[4985c98b] 2022-03-15-06-16: recursive type: a type whose value can have as part of itself another value of the same type.
[2c68e052] 2022-03-15-06-12: also stay tuned: interior mutability pattern and reference cycles. coming to a (glossary) near you!
[a9e2e072] 2022-03-15-06-11: many kinds of smart pointers in Rust. The ones focused on in the rust book are the most common: Box (Heap), Rc (reference counting for multiple ownership), Ref and RefMut, accesed through RefCell, that accesess rules at runtime rather than compile time
[a3305a4f] 2022-03-15-06-08: reference counting (pointer type): a smart pointer type that enables you to have multiple owners of data by keeping track of the number of owners and, when no owners remain, cleaning up the data.
[06d653bb] 2022-03-15-06-06: smart pointer: data structures that not only act like a pointer but also have additional metadata and capabilities.
[a8c4f5e4] 2022-03-15-06-05: pointer: a general concept for a variable that contains an address in memory.
[217d5774] 2022-03-15-06-04: okay, onto smart pointers now.
[3d83ae31] 2022-03-15-05-59: finished crates chapter. backtracking.
[fb02b5ea] 2022-03-15-05-58: binary target: runnable program that is created if the crate has a src/main.rs file or another file speciefied as a binary, as opposed to a library target that isn't runnable on its own but is suitable for for including within other programs.
[0218368c] 2022-03-14-13-04: "the yank feature is not intended for deleting accidentally uploaded secrets. If that happens, you must reset those secrets immediately". I mean, I think I understand the motivations for this, but yikes.
[79c0e9c3] 2022-03-14-13-02: I wonder if the underlying software for crates.io is open source?
[94696815] 2022-03-14-13-01: centralization of packages (crates.io) makes me go "eh?" a little bit. I wonder if there are ways to make local package repos, or some other kind of decentralized structure.
[9fb9f90d] 2022-03-14-12-58: things like 'pub use' feel like one of those things that can get complicated quickly.
[43029bac] 2022-03-14-11-37: the way the docs are so integrated into the rest of the tooling (like tests) is very cool. I like how standardized it is.
[b27a65db] 2022-03-14-07-09: Read 58% percent of the Rustbook. why does this book feel like it's taking forever to read? Well, more than halfway, so progress.
[45037dfa] 2022-03-14-07-04: documentation comment: in Rust, a particular comment format used for inline code documentation.
[c7a1f6cd] 2022-03-14-07-02: interesting that optimization levels are 0-3, like GCC/Clang. Not sure if that is deliberate or related.
[4fffa851] 2022-03-14-07-00: two main release profiles in cargo: debug and release. seems pretty similar distinctions/tradeoffs to release/debug.
[ab7519f2] 2022-03-14-06-59: release profile: predefined and customizable profile with different configurations that allow a programmer to have more control over various options for compiling code.
[be4d97dc] 2022-03-14-06-58: onto cargo + crates chapter
[5008a900] 2022-03-14-06-53: consuming adaptors: in the context of iterators, methods that use up the iterator when called. Methods that call "next" on an iterator are consuming adaptors.
[c32db956] 2022-03-14-06-40: done with iterators/closures chapter. rewinding and writing up a blurb/summary in my (rust_book) page.
[57f31eda] 2022-03-14-06-39: unrolling: an optimization that removes the overhead of the loop controlling code and instead generates repetitive code for each iteration of the loop.
[44398914] 2022-03-14-06-38: as the book describes, it is indeed nice to see the ways low-level DSP code can take advantage of high-level abstractions (with zero cost). I'm always skeptical about that sort of stuff (are you sure this is the right abstraction or way to think about it?, etc) but hey open mind.
[1269cf3f] 2022-03-14-06-36: hey look! audio domain stuff. (audio decoder on pdf page 363)
[50ec3e49] 2022-03-14-06-27: zero-overhead: the term Bjarne Stroustrup uses in his book "Foundations of C++" (2012) to describe in C++ what Rustaceans would call "Zero-Cost".
[6383c5c3] 2022-03-14-06-25: zero-cost abstraction: In the Rust Programming Language, an abstraction that imposes no additional runtime overhead.
[9b8cad7a] 2022-03-14-06-15: the "static" lifetime seems to refer to types like string constants. Is this a special lifetime name?
[4354bf80] 2022-03-14-05-59: consume the iterator.
[31f83086] 2022-03-13-15-28: iterator adapter: other methods in the Iterator struct that allow you to change iterators into different kinds of iterators.
[2e86b780] 2022-03-13-15-21: iterators in Rust are lazy, meaning they have no effect until you call methods that consume the iterator to use it up.
[8cd7c4df] 2022-03-13-15-19: closures that can capture their environment are useful in the context of iterators.
[4d14ad01] 2022-03-13-15-17: closures can explicitely take ownership of a value using the keyword move
. Apparently this gets discussed in later chapters revolving around concurrency.
[976f4dc3] 2022-03-13-15-13: Fn borrows values from the environment immutably.
[82d6819f] 2022-03-13-15-13: FnMut can change the environment because it mutably borrows values.
[0c380d10] 2022-03-13-15-12: FnOnce consumes the variables from its enclosing scope, taking ownership, and moving them into the closure when it is defined. It can't take ownership of the variables more than once, so it is only called once.
[4a99dd84] 2022-03-13-15-10: closures can capture their environment. functions do not.
[0a520eb4] 2022-03-13-15-02: All closures implmement at least one of the traits: Fn
, FnMut
, or FnOnce
.
[00cc4560] 2022-03-13-15-00: lazy evaluation: also known as memoization, the ability for a closure to compute a value only when needed to, and to other wise use a cached value.
[9385ed0e] 2022-03-13-14-56: with closures, you don't need type annotations because with their narrow scope, the compiler can usually figure it out.
[97ef22f5] 2022-03-13-14-52: the syntax for closures in rust was inspired by the closure definitions in Smalltalk and Ruby
[2b916421] 2022-03-13-14-45: iterators and closures are functional concepts specifically discussed because they are important to writing idiomatic code that is fast. (other functional things like pattern matching also exist in Rust, but are not covered in this chapter).
[5c308281] 2022-03-13-14-43: Iterators: a way of processing a series of elements
[aae46a95] 2022-03-13-14-43: Closure: A function-like constant you can store in a variable.
[d63a15ee] 2022-03-11-17-39: "iterators" and "closures" aren't entirely foreign sounding concepts to me. so that's nice.
[db7114f6] 2022-03-11-17-38: done with this minigrep chapter. now onto iterators and closures.
[26334780] 2022-03-10-15-33: the 'if let' syntax used to handle errors in the minigrep chapter is a little foreign looking to me, but it sort of makes sense in a fuzzy way.
[b26d31ef] 2022-03-09-12-36: constructors are idiomatic Rust. In other words, instead of making a function called "foo_new", have a function associated with the struct called Foo::new.
[8446e980] 2022-03-09-12-32: "we now define Config to contain owned String values". The use of the word "owned" sounds like such a rustism to me.
[f4ae0721] 2022-03-08-17-01: primitive obsession: using primitive values when a complex type would be more appopriate.
[e0beb107] 2022-03-08-14-18: maybe not though... still grokking
[50218d56] 2022-03-08-14-17: noticing the use of '&' to denote a reference I think? seems a lot more explicit than in C.
[c44cd4a7] 2022-03-08-14-14: it says to split things into main.rs and lib.rs. But what happens when lib.rs gets too big? is there a best practice for that?
[8dd2c8be] 2022-03-08-14-13: "Separations of Concerns for Binary Projects" glad there's insight for stuff like this. It feels relevant to the Boing DSP project I've been thinking about.
[edb29cb2] 2022-03-08-14-12: now reading chapter 12: Implementing a Toy Grep. My setup makes it convenient to read and type at the same time now. Since they both are well-lit e-ink displays, my eyes should be comfortable.
[f73855c4] 2022-03-08-13-48: gooseneck arrived! remarkable now can be read while I type on my e-ink display. it's all coming together now...
[789b68e0] 2022-03-08-13-22: I'm realizing my remarkable is too far away from my computer, and I need to turn my head a lot. I have purchased a goose neck stand that can attach to my tiny table so that I can both type and read at the same time. This is needed in particular for the GREP chapter.
[ad8ace1b] 2022-02-24-09-34: wrote blurb on chapter 11 (testing). chapter 12 looks like more of a hands-on chapter.
[42cd3730] 2022-02-24-09-33: integration tests: check that many parts of the library work together correctly. Use the library's public API similar to how external code will use it.
[6ab3efa5] 2022-02-24-09-32: unit test: excersize different parts of a library separately. Can test private implementation details.
[1d2009a7] 2022-02-24-09-26: correctness: the extent to which code does what it is intended to do.
[6a6cee19] 2022-02-05-14-48: the longest_with_announcement
function at the end of chapter 10 looks quite dense, and worth studying for later IMO.
[ddebee31] 2022-02-05-14-47: "in the future, even fewer lifetime annotations might be required". so, I'm assuming these become tedious to manage.
[037aefd1] 2022-02-05-14-46: "violation of memory safety"
[46c4e62b] 2022-02-05-14-45: does rust make implicit calls to malloc (or equivalent)? thinking about realtime performance. does one have to be mindful of this?
[17f298af] 2022-02-05-14-44: lifetimes are indicated by an apostrophe ('), and apparently are expected to be all lowercase and very short. Is this idiomatic then?
[2caf952c] 2022-02-05-14-42: the main aim of lifetimes is to prevent dangling references.
[af69c8da] 2022-02-05-14-42: lifetime: the scope for which a reference is valid.
[5c367ac9] 2022-02-05-14-40: finished reading about lifetimes in chapter 10, thus concluding chapter 10. circling back and reviewing.
[2197880c] 2022-01-31-14-17: lifetimes: a generic in Rust that ensure that references are valid as long as they are needed to be.
[191ab8cb] 2022-01-31-14-14: blanket implementations: implementations of a trait on any type that satisfies the trait bounds.
[9e4d3468] 2022-01-31-14-11: trait bound: a special form in Rust that is used when traits are parameters. It's a long form, and often there's synactic sugar for it "impl Trait".
[241ebf26] 2022-01-31-14-08: lol. It seems I'm still getting tripped up on where "impl" was defined. I guess it's chapter 5? Will have to look back I guess. It's sinking in at this point.
[9348ce70] 2022-01-31-14-08: traits apparently are like interfaces in other languages, not that I use many high-level languages. But I do seem to recall Go having something called interfaces that were very similar to Traits.
[28c5f9a0] 2022-01-31-13-52: Rust traits seem very much the thing to use if I want to implement something similar to the node interface I wrote for graforge in C.
[7927212e] 2022-01-31-13-51: trait: similar to interfaces in other languages, a mechanism used in Rust that tells the Rust compiler about the functionality a particular type has and can share with other types. Can be used to define shared behavior in an abstract way.
[1cd7c915] 2022-01-31-13-50: monomorphization: the process of turning generic code into specific code by filling in the concrete types that are used when compiled.
[35649cf0] 2022-01-31-13-49: it's interesting to know that there's no performance overhead in using generics. I've heard that compilation times are slow though, so I wonder if there's a penalty there?
[de90e203] 2022-01-31-13-48: I am confused by code example 10-11. I wrote the comment "okay... this could get complicated quickly". It looks like I was getting tripped up by all the generic variables T, U, V, and W and how they relate.
[e6513dac] 2022-01-31-13-44: I guess "impl" was used already in chapter 5 when implementing methods in structs. I clearly have forgotten that already.
[da18bfe2] 2022-01-31-13-43: Generics in Enums are a little bit strange to me. I'm really used to C Enums. Giving them types all of a sudden confuses me.
[76ecb7e8] 2022-01-31-13-41: integer and floating point notation is often interchangeable in so many languages, I wasn't yet sure if they could be interchangeable in 10-6. Next page answered my question.
[0f569073] 2022-01-31-13-36: The generics chapter is a pretty meaty chapter. Found my way up to lifetimes, and thought it was a good time to review and re-read my scribbles.
[a7c61ce5] 2022-01-24-16-40: onto chapter 10. halfway through pretty much!
[bf3b83a5] 2022-01-24-16-35: backtrace: a list of all the functions that have been called to get to this point.
[2dad3c26] 2022-01-24-10-51: now on error handling
[18e613ec] 2022-01-24-10-50: SipHash: default hash used in Rust, designed to be resilient against DoS attacks. This algorithm is a tradeoff of security over performance.
[9b8e4cc5] 2022-01-24-10-49: hashmap uses SipHash by default, which favors security over performance. this can be changed with something called a hasher
.
[94328768] 2022-01-24-10-49: hashmaps. the example in the book uses a hashmap to store scores as integers. but there is no type definition. so is the type annotation implied?
[3dae3dab] 2022-01-24-10-47: grapheme cluster: a unit of measurement for strings in Rust. A close analagy would be a letter. Things like Devanagari script that use diacritics can have grapheme clusters with a variable number of bytes.
[6a03fca4] 2022-01-24-10-45: rust considers strings to be bytes, scalar values, and grapheme clusters (letters, more or less).
[dc41ca67] 2022-01-24-10-44: strings are painful for programmers coming from C-like languages because strings are just byte arrays and thats the end of the conversation. Meanwhile, Rust aims to support strings as things that embed language, which goes beyond just ASCII and byte streams.
[aad7c228] 2022-01-24-10-42: enums are how you get vectors of multiple types. will have to look at that more closely.
[3e4a56a1] 2022-01-24-10-41: May have to check out the Rustonomicon
[014627e0] 2022-01-24-10-41: vectors seem very familiar (as in flexible arrays, not math vectors). bounds checking and the like seems to be trickier than usual.
[92101953] 2022-01-24-10-38: am now in the rustbook chapter on various collections. I have read now, now I am logging various notes here.
[13a42462] 2022-01-20-13-04: rustbook just dropped the concept of deref coercion
, which apparently gets discussed more in detail in chapter 15. It sounds similar to recasting and type punning in C, but more formal and strict (obviously).
[09a6efbd] 2022-01-20-12-59: type annotation: in rust, this refers to explicitely labelling what something is, such as
.
[1507a56a] 2022-01-12-09-58: next paragraph uses the word 'convention'. methinks so.
[7446f271] 2022-01-12-09-57: does idiomatic conventional?
[e5076bc4] 2022-01-12-09-50: "enums aren't useful unless their variants are public". need to remember what an enum variant is.
[d2969975] 2022-01-12-09-45: I'm still how super is working with serveorder without the namespace?
[7b3cc1a5] 2022-01-12-09-34: privacy boundary: the line that encapsulates the implementation details isn't allowed to know about, or rely on.
[9b810c9b] 2022-01-11-15-11: to look up items in a module tree, rust employs both relative and absolute paths. absolute is done using a crate name or the literal crate
. A relative path starts from the current path and uses self
, super
, or an identifier in the current module.
[b103efb5] 2022-01-11-15-07: modules nest. huh. interesting.
[4370bd89] 2022-01-11-15-04: create a new library restaurant: cargo new --lib restaurant
.
[cb67d041] 2022-01-11-15-02: privacy (rust): in the context of modules, the determination whether an item can be used by outside code (public) or not.
[cc3aca12] 2022-01-11-15-01: modules (rust): thing that organizes code within a crate into groups for readability and easy reuse.
[949d3606] 2022-01-11-14-57: package: one or more crates that provide a set of functionality.
[91a05de6] 2022-01-11-14-56: crate: a binary or library.
[2fc9309e] 2022-01-11-14-56: crate root: source file that the rust compiler starts from and makes up the root module of your crate.
[b380fa20] 2022-01-10-16-36: currently at chapter 7. also took the time to update the (rustbook) page with chapters and some quick words. it turns out the Rust Book PDF I made doesn't have the TOC or any mention of chapter number after the intro?
[39a15e21] 2022-01-05-11-13: oh. now the page is okay. weird. ugh.
[416423a4] 2022-01-05-11-12: not sure why this (rustbook) page renders small text on mobile. stupid web.
[17c89f14] 2022-01-05-10-18: made this rustbook label.