简体   繁体   中英

To what extent is Rust shadowing zero-cost?

A Zero-Runtime-Cost Mixed List in Rust outlines how to create a heterogenous list in Rust using tuples and normal traits (not trait objects like this question suggests). The list seems to rely heavily on shadowing and effectively changes the entire type of the list every time a new element is added.

The implementation seems brilliant to me, but after reviewing a few Rust's homepage and resources I could not find anyplace that explicitly defines shadowing as zero-cost. As far as I know, repeatedly abandoning data on the stack is less costly than indirection, but repeatedly copying and adding to existing data instead of mutating it sounds pretty expensive.

What you don't use, you don't pay for. And further: What you do use, you couldn't hand code any better.

  • Bjarne Stroustrup

Shadowing seems to fulfill the first requirement, but the second?

Is Rust's shadowing actually zero-cost?

Official Rust material tries very hard to never talk about "zero cost" by itself, so you'll have to cite where you see "zero cost" without further qualification. The article states zero runtime cost, so the author of the post is aware of that. In most cases, "zero cost" is used in the context of zero-cost abstractions .

Your Stroustrup quote only partially and obliquely deals with zero-cost abstractions. A better explanation, emphasis mine:

It means paying no penalty for the abstraction , or said otherwise, it means that whether you use the abstraction or instead go for the "manual" implementation you end up having the same costs (same speed, same memory consumption, ...).

This means that any time you see "zero-cost abstraction", you have to have something to compare the abstraction against ; only then can you tell if it's truly zero-cost.

I don't think that shadowing even counts as an abstraction , but let's pretend it does (and I'll word the rest of my answer as if I believe it is).

Shadowing a variable means having multiple distinct variables with the same name, with the later ones precluding access to the previous ones. The non-"abstract" version of that is having multiple distinct variables of different names. I'd say that having two variables of the same name is the same cost as having two variables of different names, so it is a zero-cost abstraction.

See also:


Playing the game further, you can ask "is having two variables a zero-cost abstraction?". I'd say that this depends on what the variables are and how they relate.

In this example, I'd say that this is a zero-cost abstraction as there's no more efficient way I could have written the code.

fn example() {
    let a = String::new();
    let a = a;
}

On the other hand, I'd say that this is not a zero-cost abstraction, as the first a will not be deallocated until the end of the function:

fn example() {
    let a = String::new();
    let a = String::new();
}

A better way I could choose to write it would be to call drop in the middle. There are good reasons that Rust doesn't do this, but it's not as efficient in regards to memory usage as a hand-written implementation could be.

See also:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM