Skip Navigation

What Rust calls "reference" is a much more specific thing, that is not so general-purpose.

users.rust-lang.org Perpetual n00b struggling with ownership (again)

Other languages use term "reference" for storing things "by reference" or just referencing any object anywhere in general. It's not like that in Rust. What Rust calls "reference" is a much more specific thing, that is no so general-purpose. It has a narrower, restrictive usage. Rust references are ...

A nice comment in a forum thread (extracted below, but also see the shorter more facetious version below that) about references and their lifetimes in structs. Here is a link to the full thread over on users.rust-lang.org

I feel like I needed to hear or read this, and I feel like this sort of clarification is not put front and centre enough in rust learning material (as others in the thread say too). "The Book" certainly doesn't seem interested in clarifying perspectives like this.


The Comment

Other languages use term "reference" for storing things "by reference" or just referencing any object anywhere in general. It's not like that in Rust.

What Rust calls "reference" is a much more specific thing, that is no so general-purpose. It has a narrower, restrictive usage. Rust references are more like read-only or write-exclusive locks. They make their target unmovable and immutable for entire duration of their existence. They can't exist on their own, only as a counterpart of an owned value.

References in structs also make the whole struct itself temporary, and everything that touches that struct becomes temporary and tied to the scope of the borrowed value that started it.

If these restrictions (that cause you fight with the borrow checker) aren't what you want to achieve, then you don't want temporary references.

99% of the time when you need to store something "by reference", Box (or Arc or String or PathBuf or Vec or some other owned type) is the right answer.

Note that &T and Box<T> have identical representation in memory — a pointer. They differ by ownership.

In Short

From here

You're not allowed to use references in structs until you think Rust is easy. They're the evil-hardmode of Rust that will ruin your day.

😉

Use Box or Arc to store things in structs "by reference". Temporary borrows don't do what you think they do.

12 comments
  • Hmmm. On the one hand I heavily agree with the analogy to read only and write exclusive locks (I think I gave it myself in the ownership chapter recap/discussion thread). On the other, I feel like this is singling out "references" for something that is much broader in cause.

    I could just as easily say that references in rust are "just" references, and that it's the rules around ownership (like the compiler automatically dropping things when changing scope) that restrict what you can do with them, in practice.

    I dunno, given rust's history and explicit purpose of preventing memory errors, notably in multi threaded code, if you still assume you can just take a reference to "any object in memory" and do whatever you want with it then you either haven't paid enough attention to how the book introduces references or maybe rust isn't cut out for your way of thinking.

    There are ways to do raw pointers in rust if you need to. But then you need to more or less do all of the compiler's job yourself, notably figuring out when you can safely free that memory.

    In other words, references don't exist on their own, and so how the author describes them "in other languages" feels to me like they never had to implement a language themselves and safely deal with shared references, nor use them that thoroughly in a language with "general" references like C. Otherwise I don't think they would have developed this mental model that expects references to be considered their own thing, almost separate from the underlying data.

    I can't tell if the author is inexperienced with languages that "do a lot" and have a more cohesive design, or is so much more knowledgeable and experienced than I that they've already taken this into consideration and are arriving at this point regardless.

    • I got the feeling from the thread that the author's perspective and framing is coming from having to help many people with their problems and likely misuses and misunderstandings of rust references, where your point of not having "paid enough attention to how the book introduces references" may be applicable to many of the people they've helped.

      For me, while there isn't anything conceptually new in their framing, I found the emphasis and perspective helpful and affirming, in part because I hadn't got to the point of verbalising the "locks" metaphor as you say you probably did but instead was still thinking of it all as a set of constraints to work within and problems to avoid. Framing the situation in a more "active"/"positive" (as in posit) way where the emphasis is on what references "do" rather than just on what they "prevent" seems helpful to me, and that's the part that I feel like is missing from "The Book" or anything else I've read. It also feels like a better way of explaining why lifetime annotations become necessary (generally wondering which being how I ended up reading those threads)

      • I finally clicked over to the thread, and you're totally correct; the author is clearly talking about their collective encounters with newcomers rather than their own rust "journey".

        This makes me want to share a growing hunch of mine: rust is, currently, made by and for someone like me, who's had the privilege of developing a (rudimentary) working knowledge of the fundamentals involved in how today's computers work, from the physics involved all the way up to something like OCaml or python, before ever hearing about Rust itself.

        More specifically, there's so much that The Book leaves assumed-yet-unsaid, even when it really tries to provide background and rationale for concepts.

        I don't think it's reasonable to expect [The Book's writing team] to properly teach everything that it later relies on, and it already does say that it expects a certain level of programming experience from the reader near its very beginning. I think it could use a more explicit and concrete list of "requirements", though, like a dependency tree of prior concepts to acquire. Maybe that could help it strike a better balance between over- and under-explaining things.

      • Ahh, that makes a ton more sense to me! Thanks.

        I like your verbiage regarding "things you do" vs "an [ambient] set of constraints", and I would go one further (or in any case my mental model is): there are a set of valid states or configurations for references that is smaller than (and contained within) the set of possible or imaginable configurations.

        By configuration, here, I kinda literally mean "the state of the program/machine executing the program, as that execution plays out". So, "3 read-only borrows of some piece of data" is a valid configuration, while "2 simultaneous mutable borrows" is an invalid state for the program to be in. It's sort of the same conceptual approach as types: you express the valid/allowed configurations that are (almost always) a subset of the overall possible states. Except in this case, it's the language that has defined it once, ahead of time, rather than us programmers who define things as we go. Maybe that just gets us back to the same point that wasn't originally clicking for you, though.

        Sidenote: I wonder if a language could be developed that allowed the programmer to define or setup their own set of constraints around lifetimes and references. Sort of like what Zig seems to allow for memory allocator/allocation strategies, but specifically for ownership semantics. As I type this out, I can't shake the feeling that this is basically what Rust has already done with their & vs &mut vs Box vs RC vs RefCell etc. It's not like there is a way to safely have 2 mutable references to the same memory/variable that is both general and simpler than existing mechanisms.

        Re: lifetime notations, it's good to know that this helped you. For me it was the combination of encountering the particular part in chap 4 of The Book where they examine the case of a function that accepts a tuple and returns a ref to the first element (or something along those lines), and trying to define (and then use) a struct that would store a ref to some other data in a hobby project.

        Overall, this makes me realize how much of Rust I have already internalized!

12 comments