About books, and Jon Gjengset about memory

As I might continue using Rust, at least for the next 12 months, it might make some sense to read one more book in next winter. Mara Bos's book might be still too advanced for me. The upcoming new release of Jim Blandies book might be an option -- I think his current second release is quite good, maybe one of the best Rust books -- but very detailed and a bit verbose. And then there is the book of Jon Gjengset, which is sometimes recommended. I just read a few pages at Amazon.com:

Talking About Memory

Not all memory is created equal. In most programming environments, your programs have access to a stack, a heap, registers, text segments, memory-mapped registers, memory-mapped files, and perhaps nonvolatile RAM. Which one you choose to use in a particular situation has implications for what you can store there, how long it remains accessible, and what mechanisms you use to access it. The exact details of these memory regions vary between platforms and are beyond the scope of this book, but some are so important to how you reason about Rust code that they are worth covering here.

Memory Terminology

Before we dive into regions of memory, you first need to know about the difference between values, variables, and pointers. A value in Rust is the combination of a type and an element of that type’s domain of values. A value can be turned into a sequence of bytes using its type’s representation, but on its own you can think of a value more like what you, the programmer, meant. For example, the number 6 in the type u8 is an instance of the mathematical integer 6, and its in-memory representation is the byte 0x06. Similarly, the str "Hello world" is a value in the domain of all strings whose representation is its UTF-8 encoding. A value’s meaning is independent of the location where those bytes are stored.

A value is stored in a place, which is the Rust terminology for “a location that can hold a value.” This place can be on the stack, on the heap, or in a number of other locations. The most common place to store a value is a variable, which is a named value slot on the stack.

A pointer is a value that holds the address of a region of memory, so the pointer points to a place. A pointer can be dereferenced to access the value stored in the memory location it points to. We can store the same pointer in more than one variable and therefore have multiple variables that indirectly refer to the same location in memory and thus the same underlying value.

Consider the code in Listing 1-1, which illustrates these three elements.


I had to do picture to text conversion, but I think that text segment is converted correctly.

As a non native speaker, I am not sure if I should really be happy with some of the sentences. And I don't know if he is a native speaker -- from his name I have some doubts.

Not all memory is created equal.

Is that really a good phrase? Do we really create memory? Is allocating not more correct?

A value in Rust is the combination of a type and an element of that type’s domain of values.

I do not like that sentence too much, but it is correct.

A value can be turned into a sequence of bytes using its type’s representation, but on its own you can think of a value more like what you, the programmer, meant. For example, the number 6 in the type u8 is an instance of the mathematical integer 6, and its in-memory representation is the byte 0x06.

Again, correct, but is that really a nice phrase?

The most common place to store a value is a variable, which is a named value slot on the stack.

Would that imply, that each variable is always stored on the stack? I am a bit unsure -- in the past I called an array element like a[i] a variable as well -- but I am not sure if I was correct.

We can store the same pointer in more than one variable and therefore...

Yes, that is correct. But when first reading that sentence, I got a strange feeling -- I have no real idea why. I would have typically said "We can have multiple pointers referring to the same memory region..."

Well, generally that text section is correct, and I think it was created in 2022 without any AI assistance. But still, I am not convinced that I should buy and read their book.

At the end, a funny fact. I was recently pointed to a comment in LWN.net about my own book. (That website is currently unavailable -- seems to be a low quality medium.) That person thinks, that to write an excellent Rust introduction, one would need at least a decade of Rust experience, a few possible tiny errors in a book would be a disaster, and that AI assistance for writing is general evil. I think they never looked into my book, but were sure it must be bad. Well, I am very skeptical about all the hundreds Rust books at Amazon as well, but that guy seems to be not too smart :slight_smile:
Writing an excellent Rust introduction is no rocket science: Rust is complex, and a bit difficult, but the content of beginner books, like the official tutorial, it quite trivial. What is most important is, to have a clear target audience, to dedicate a few hundred hours of your time, and to explain the stuff correct and in a way that is easy to understand for the reader -- and enjoyable to read.

"Not all $X are created equal" is an English phrase which, here, just means the have different behaviour and use cases that must be considered. "Not all kinds of memory are the same". That is, one must distinguish between the different kinds of memory:

Which one you choose to use in a particular situation has implications for what you can store there, how long it remains accessible, and what mechanisms you use to access it.

It's not talking about allocation or anything like that. The use of "created" here is, I would assume, "God's creations" (etymologically speaking).

Notionally. It might end up being in a register or optimized away altogether. I wouldn't call a[i] a variable. Depending on the context of the conversation, I'd call it a place or an expression (that evaluates as a place), etc.

(A variable is also a place.)

After making such a big deal over values being independent of locations, I find it odd that this was phrased using variables specifically.


My take on the quoted portion is... it's unclear who the audience is. Bits like this:

A value’s meaning is independent of the location where those bytes are stored.

Make it feel like it's sort-of correcting the (official) Book's over-emphasis[1] on heap versus stack. But if so, why assume that context?

And other things just make me feel like the audience isn't well defined. Like, we'll sort of assume in passing you know what the stack and heap are. But we're going to have a side bar on a value's representation in terms of bytes? Why the emphasis on value domain? Are we going to be talking about typed and untyped memcpy or something?

How does this all relate to the focus of the rest of the book?

I think this is a common thing for books to struggle with though. The official Book also struggles.

(Assuming this is Rust for Rustaceans, I actually have the 2022 first printing. But I haven't read it since I reviewed the e-book pre-print.)

The most common place to store a value is a variable, which is a named value slot on the stack.

Depends on your programming area, but I doubt that. My guess would be that, typically, most values are in heap allocating data structures.

(OTOH "store" is vague here. The fields of a tuple in a variable are not themselves variables. Are they stored in the variable? The str data of a String variable is on the heap. Is that stored "in the variable"? I suppose one could argue that the sentence is just too imprecise to be meaningful at all, relative to the rest of the surrounding content.)


  1. to the point of inaccuracies ↩︎

4 Likes

This is a variation on an idiom that may be more recognizable to Americans, because it alludes to the second sentence of the US Declaration of Independence:

By the way, I really like your book!

1 Like

I think Rust for Rustaceans is a great book to read if you want to dive deeper into Rust. I wouldn't think of it as a manual or a tutorial, but rather as a source of inspiration for new things to think about and look into.

The author is not only very experienced in Rust, but is also a talented and precise educator. And David Tolnay was the technical reviewer for his book, so you know there was a knowledgeable proofreader.

4 Likes

I've got a hard copy around here somewhere, IIRC at the start it explicitly says something like the target audience is people who know the stuff from The Book but want a deeper understanding. Based on that, I'd read those statements as essentially trying to correct some common assumptions about what a value is - so it's addressing the understanding of "a value is a set of bytes" etc. with the distinction between a value and it's representation. Talking about the type is probably to distinguish between abstract values like 7 and specifically 7u32.

I don't have enough context to say if that actually gets used but I generally remember it being pretty well put together.

2 Likes

Can I summarise variables, values and type like so:

A "variable" is a named thing. For example bonzo here:

let bonzo: Dog;

Where Dog is the kind of the thing being named. A type. In this case a dog.

A "value" is a state of the thing. Like so:

bonzo = 3;

The value has to be a possible state of the type of the thing. In this case 3. Which is allowed because I secretly defined the type Dog like so:

type Dog = u32;

Can we think of elements of an array as "variables"? I'm not sure. The array is a named variable but hose elements have values but they have no name.

1 Like

At Google books we can read larger parts of their book, see

Unfortunately the text can not be selected and copied.

After reading a few pages, I have the feeling that the book is in part a good companion to the official Rust book/tutorial. But parts are a bit strange, e.g. page 3, with the heading “High-Level Model”. For that section the target audience is quite unspecific. Someone who has learned as a beginner from the official book, would still have problems understanding that section. And for someone with some prior experience, there is not much new to learn.

What I learned from reading a few pages, is that Rust has the concept of “Places” for unspecific locations where a value can be stored. So an array element like a[i] is a place, but we typically call it not a variable. I think that makes sense.

The Crust of Rust series has a lot of great info, but the format is not ideal for me (longer videos, combined with the slower pacing of the live streams), so I was excited to hear about Rust for Rustaceans and decided to pick it up.

As it says in the intro: “Rust for Rustaceans picks up where The Rust Programming Language leaves off.” The author presumes the reader is familiar with the Rust book, and targets the content towards developers with months to years of experience coding in Rust. The book presents heuristics, best practices, and makes crate recommendations where the official book cannot, which is why the subtitle refers to Idiomatic Programming.

For instance, the chapter on Error Handling is only seven pages, and focuses on classifying the most common error handling patterns along with some brief advice on when to reach for each tool. The chapter on Project Structure does not reintroduce you to modules, but rather delves into subjects from the Rust book that left me wanting more… like features, workspaces and build configuration.

For the following chapters (on Testing, Macros, Async etc.), the book stays true to the spirit of the video series, in that the author cannot resist adding a “How it Works” section to every subject and taking the reader under the hood for a look. The point is not to write your own testing harness, or async executor, but to gain some intuition for why the API we rely on works the way it does, and following from that how to use it well.

The style of writing can be quite information packed, and would make a good beach blanket read, but might be less enjoyable as a bed time book. For fans of the video series, Jon Gjengset almost starts to feel like a friend, because of the passion and warmth that he brings to the subject, and that enthusiasm translates well into the written work.

3 Likes

Thanks for mentioning that link. I already heard that they made a Rust videos series – but I typically are not watching programming videos. For me, programming videos are either boring, or I have problems following complicated topics, which results partly from the fact that I am not a native English speaker.

The fact that they produced free videos is indeed a motivation to buy their book. I think that book has sections about async and macros – the two topics which I have not studied yet. Til now I read only a few pages at Google Book from the beginning of the book – not much new information for me, and their writing style makes it not too easy to follow, even for stuff we already know well. E.g. citing page 6:
”
Static Memory
Static memory is really a catch-all term for several closely related regions
located in the file your program is compiled into. These regions are
automatically loaded into your program’s memory when that program is
executed. Values in static memory live for the entire execution of your pro-
gram. Your program’s static memory contains the program’s binary code,
which is usually mapped as read-only. As your program executes, it walks
through the binary code in the text segment instruction by instruction and
jumps around whenever a function is called. Static memory also holds the
memory for variables you declare with the static keyword, as well as certain
constant values in your code, like strings.“

That is correct, but I wonder if I could understand it easily as a beginner :slight_smile:

For comparison, below is a rewrite generated after a short discussion with an AI. At least for me that is much easier to read and understand:

Static Memory (Improved Rewriting)

Static memory refers to several related sections of your program's compiled binary that are loaded into memory when the program starts. These sections stay in memory for the entire duration of the program’s execution. One of them contains the program’s machine code, typically mapped as read-only, which the processor follows instruction by instruction—jumping when functions are called. Static memory also holds data for variables declared with the static keyword, as well as certain constants, like string literals, that are embedded in the binary.

The Rube-Goldberg complexity of the English is a signature part of the author’s voice, and part of how you can tell every paragraph in the book originated from him. It is written like he talks, without reading like a condensed series of lecture notes.

If we were to compare literary styles with the Rust book, Carol Nichols et. al write like Hemingway. Everyday language, plain and simple, easy to understand. They intentionally reduce the complexity of writing to broader their audience, casting a wider net. On the other hand, Jon Gjengset is probably closer to James Joyce. Some will tell you the complexity is part of what makes it good, but no one is accusing Finnegan’s Wake of having a broad audience.

The density of the prose is what made it a challenging nighttime read, and if English is a second language for you, I think it is legitimate to be concerned, though not disqualifying. With a little time and caffeine, it’s a great read.

2 Likes

The two versions read about the same to me but the second has less information and nuance - but then I also talk like Jon a lot :sweat_smile:

I would say it's not quite a book for the beginner, though: the “where the Rust Book leaves of” quoted above is more rhetorical than literal. It's really meant as a book for when you have read the Book, have developed some experience using Rust, but are running into enough trouble that you're looking for guidance on how to avoid that. If it's not an intermediate book, it's a “how to become an intermediate” book.

I do like his streams a lot in general: they're often very long but go into a very deep level of detail slow enough that you can follow without already knowing it, and it's often about things that you can't get anywhere else in one place, short of reading the crate source code for a day or two for the Crust series.

2 Likes

Interesting. Actually I just noticed that I can follow his English videos quite well, while for most English videos at YouTube I can understand only fragments.

Jon is from Norway. English is his second language. As is often the case such people speak English very beautifully and in a way that is clear to everyone. No lazy pronunciation or slang as native speakers might have.

8 Likes

I really like the way Jon thinks and tackles problems, especially in his videos, and I like his book, but it’s quite hard to read. I started reading it right after learning Rust, and I thought perhaps it was a bit too early. But even when I read it now, I wish it was more didactic; if you compare to David Drysdale’s Effective Rust, it’s night and day.

There are quite a few long sections of dense paragraphs without any example or illustration to clarify them, so I also have the impression it’s a very good book if you already know most of the content and have something to cling onto. And I’m used to learning with relatively old-fashioned text material, so it’s not as if I needed a fancy animated PowerPoint to learn stuff. I suppose the idea is to read a bit, then experiment with code on the side to accompany the text with something concrete. Maybe it’s a way to force the reader to be more active to enhance the understanding (I had a professor at uni who did that a lot, which worked, but not for everybody :smiley:).

There’s no denying it’s full of valuable information, though.

2 Likes

In think the pages 9 up to 14 are actually quite good (note, Google books has the first 50 pages available), but I am not fully happy with the following comment to listing 1.9:

When we reassign z later, we are creating an entirely new variable that exists only from that point forward. It just so happens that that new variable is also named z.

There is no `let` keyword involved. Should we not better just say “to satisfy the borrow checker, we have (formally) to reassign &x to z, after we modified x? Or we might say something like “we reassign or update the binding”. But saying “we are creating an entirely new variable” sounds strange.

Gjengset is using the term “places”, and I think that a variable is always a “place” (storage location). So when they say “creating an entirely new variable” they would create a new storage location as well, which for me is just wrong.

2 Likes

That sentence starts with the phrase “this aligns perfectly with the data-flow model of memory we discussed earlier”, referring to the section “High Level model” at the end of page 3.

This describes an alternative model of thinking about variables and values as graphs of dependencies between write and read accesses to a value, a definition that is more useful when attempting to understand ownership rules than thinking about memory locations. I might say it's more precise to say it's an empty variable just to make it clearly distinguished from shadowing, which does behave differently.

This model almost certainly comes from the internal model nearly any optimizing compiler actually uses to represent your code, so it's probably actually a more accurate way to think about variables than what a CPU does. If you want to look this up, static single assignment - “SSA” - is a pretty easy to search for version of this, but there's a bunch of other similar models.

1 Like

My main gripe with that example is:

When then move out of x at (3), which ends the lifetime 'a because it is no longer valid.
[...]
When x is moved, z stops existing.

  • x is not moved out of, nor moved itself. It is overwritten. The old Box is dropped in place.
  • The lifetime ended (had a hole) after the println because z was overwritten before any further uses, not because x was overwritten. In compiler parlance, because z was dead.
    • More generally, uses of the referent can conflict with being borrowed, but don't determine the duration of the borrow.

Buuuuut... maybe none of that is really a problem for some given mental model. For a non-compiling example, "the borrow was active, but conflicts with this use" and "the use killed the borrow, but the borrow needed to be active" can be considered different ways to say "the borrow constraints and the uses are incompatible".

(Then again, the book claims it is describing how the borrow checker actually works.)

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.