What is the principle of failure in the way variables and data interact with movement?

I just came into contact with the knowledge of ownership, and learned that in the interactive mode of movement, when the owner of the median value of Rust changes, the old owner will become invalid. I have tried to understand the principle of failure and read some materials, but have not found relevant answers. I would like to ask what is the principle of failure and how to achieve the failure?

What do you mean by "interactive mode of movement"? Wha is "the median value of Rust"? What kind of "failure" are you talking about? Your question is not comprehensible. If you are having trouble expressing yourself in English, please seek (human) help.


(Not 100% sure what your asking.)
If the old variable does not become invalid then you will allow subsequent code that allows overlaps of read/write. Rust compiler optimizes based on it not happening. To get similar optimization in other languages you have to perform alias analysis on the generated machine code.

I'm sorry for my poor English expression. I tried to express my thoughts again.
In Chapter 4 of The book The Rust Programming Language, the author describes What is Ownership as follows:

Where the lines are drawn in the figure it says, "Rust considers s1 as no longer valid." What I want to know is, how does Rust invalidate s1

1 Like

I'm sorry for my poor English. I will study English hard after that. Next I will try again to express my thoughts.
In Chapter 4 of The Rust Programming Language, the author describes What is Ownership as follows:

I want to know how the part of the graph that draws the lines invalidate s1
Again, sorry for my poor presentation

The compiler keeps track of which variables have been moved from (like s1), doesn't let you use the ones that have might be moved from, and only drops the ones that are still valid.

fn foo() {
    let s1 = String::from("hello");
    let s2 = s1;
    // Now that `s1` has been moved from, it is considered uninitialized
    // as if you hadn't every assigned a value.
    // All program flow from here on has to have passed through that
    // move so it's easy for the compiler to know you shouldn't be able
    // to use `s1` anymore and that it doesn't need to drop `s1`.
    // ...
    println!("{}, world!", s1); // Error

A lot of times this can all be known at compile time. When it can't be known at compile time if something has been moved or not, it keeps track by compiling some "drop flags" into your function.

Here's another recent thread on the topic.


Thank you very much for your answer.

Invalidation is not something that happens at runtime (usually – there are exceptions). Whether a value is valid is recorded in the state of the compiler, at compile time. The compiler builds a series of abstract representations of the code (eg., an AST, HIR, MIR, and possibly more).

Operating over these representations, it is possible to check which variables are initialized, uninitialized, and moved-from at each point in the program. When a variable is moved from, it is considered uninitialized until it's assigned a value again. It is merely this consideration that matters from the compiler's point of view – what it will allow and forbid to do with the variable.


Thank you very much for answering my question :smile:

If the question is how to interpret the diagram in the original post, so regarding the notation in this diagram

the fact that s1 is considered "invalid" in the program state that this diagram represents is represented by the gray background color of the s1 value and its fields. The idea behind using a gray color here, instead of for example just removing the moved value entirely, is that the value still exists in (stack) memory at run-time, but the (mostly) static analysis of ownership that the compiler does considered it "invalid" data now. The effect of this "invalid" state then is that the data that might still exist on the stack memory at run time is however going to be ignored, and inaccessible, and there won't be any destructors executed when it goes out of scope.

Where is the piece you explained reflected in the rust source code? I would like to learn and understand it in more depth with the source code.

It's not one piece of code. Basically, almost all of the compiler is about creating, analyzing, and transforming different IRs. The Rust compiler isn't an easy project to read even for someone well-versed with the principles of compiler architecure. (I have written some toy and non-toy compilers before, and I find it highly non-trivial to navigate Rustc's source, simply because of the sheer volume.)

So I can't really point to one specific place, and I wouldn't advise beginners to start learning the language by reading the compiler's source code. Read tutorials and write Rust code yourself, and read smaller project's code to find out what is and isn't idiomatic. That way you'll be able to build an intuition as to how things work. This will be much more productive than trying to reverse engineer the language from the compiler.

1 Like

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.