4 ms·
The complete function definition is provided in the documentation there, and it isn't defined in terms of Drop. It's just a single line function with an empty b
by coder543 4y ago
The complete function definition is provided in the documentation there, and it isn't defined in terms of Drop. It's just a single line function with an empty body.
In fact, mem::drop will accept any value, whether it implements Drop or not.
The author of the article is definitely quite confused about Drop vs mem::drop. mem::drop is not an implementation of Drop.
- woodruffw 4y agoOh, I see what you mean: it does look like they've confused `mem::drop` with an implementation of `Drop`. > In fact, mem::drop will accept any value, whether it implements Drop or not. This doesn't mean that it isn't defined in terms of Drop, because there is no such thing as !Drop in Rust. Even things that are Copy are implicitly Drop, it's just that the copy is dropped instead of the value.
- coder543 4y agoI think your second paragraph is a misinterpretation of how Rust works. Everything isn’t implicitly Drop. Drop is an explicit cleanup mechanism that types can opt into. If it helps you to think of it conceptually as everything having an implicit no-op Drop, then I guess that’s fine, but that’s not what is happening. There is an automatic Drop “glue code” for types that contain types that implement Drop, so that those will get called, of course. But `i32` does not have Drop, at all. > Even things that are Copy are implicitly Drop, it's just that the copy is dropped instead of the value. You cannot implement Drop on a Copy type, so Drop literally never gets called on Copy types. You can’t put non-Copy types inside a Copy type, so there isn’t even Drop glue code. And no, it isn’t implicitly Drop at all! And it has nothing to do with a copy being dropped instead of the original value. Drop isn’t a universal trait. I also seem to remember in the early post-1.0 days that whether a type implemented Drop or not would significantly impact lifetime analysis, requiring some occasionally obtuse workarounds. Rust lifetime analysis accepts many more correct solutions these days, and it has been awhile since I wrote a lot of Rust code, so I don’t recall how it is these days.
- woodruffw 4y ago> If it helps you to think of it conceptually as everything having an implicit no-op Drop, then I guess that’s fine, but that’s not what is happening in the generated code. I understand that types that don't implement Drop do not literally have an implicit `Drop` trait implemented for them by the compiler. What I meant is that there is no "undroppable" type in Rust: the best you can do is make the type panic in a custom Drop implementation, but any function that takes ownership of a value is effectively described as forwarding, dropping, or forgetting that value based on the lifetime/type of its return. In other words, `mem::forget` can only be defined in terms of Drop (or default drop behavior for a type) in terms of ownership semantics, because its signature admits no other possibilities.
- coder543 4y ago> In other words, `mem::forget` can only be defined in terms of Drop (or default drop behavior for a type) in terms of ownership semantics, because its signature admits no other possibilities. But again, Drop is a destructor trait. It might be confusing that this shares a name with the concept of "dropping" in Rust, which is when a value goes out of scope, but they're not the same thing. Not every value has Drop, and mem::drop doesn't just work for values that are Drop. It is not defined in terms of Drop, but just Rust's ownership semantics. In fact, you can define a `drop` function that only accepts Drop types: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d04ba37c7e7abdad43b70defd8d3c5e5 https://play.rust-lang.org/?version=stable&mode=debug&editio... Although I am disappointed that the automatically generated Drop glue doesn't "count" for this purpose, and there isn't a higher level Drop trait, so this isn't a fully general solution. I also don't know where the concept of "undroppable" came from for this conversation. Taken literally, that would mean that the compiler would emit an error any time a value of that type would need to be dropped, so those values could only exist in functions that either return them or return `!`, or as global static values. I never suggested that was a possibility, and Rust does not support types that are undroppable, but it does support types that are not Drop.
- woodruffw 4y ago
- steveklabnik 4y ago> Even things that are Copy are implicitly Drop, it's just that the copy is dropped instead of the value. While that mental model could make sense in an abstract way, it's not literally true. Copy types are forbidden to implement Drop. fn takes_drop<T: Drop>(t: T) { todo!() } fn main() { takes_drop(5i32); } gives error[E0277]: the trait bound `i32: Drop` is not satisfied --> src/main.rs:6:20 | 6 | takes_drop(5i32); | ---------- ^^^^ the trait `Drop` is not implemented for `i32` | | | required by a bound introduced by this call | note: required by a bound in `takes_drop` --> src/main.rs:1:22 | 1 | fn takes_drop<T: Drop>(t: T) { | ^^^^ required by this bound in `takes_drop`
- woodruffw 4y agoThanks for the example! Yeah, I'm realizing my framing (around the Drop trait, and not "droppability" as a concept) was incorrect. Would it be more accurate to say that Rust guarantees the droppability of owned values? I know there's a guarantee that &'static items never have their underlying value dropped, but that works because you can never actually hold the static value itself, only its reference.
- steveklabnik 4y ago> Would it be more accurate to say that Rust guarantees the droppability of owned values? I'm not really sure, exactly, since "droppability" isn't really a thing that's talked about, because as you're sort of getting at here, it's universal, and therefore not really an interesting concept. > I know there's a guarantee that &'static items never have their underlying value dropped, Even this is sort of... not correct. Consider this program: #[derive(Debug)] struct Boom; impl Drop for Boom { fn drop(&mut self) { println!("BOOM"); } } use std::mem; static mut FOO: Boom = Boom; fn main() { let mut s = Boom; unsafe { dbg!(&FOO); mem::swap(&mut FOO, &mut s); dbg!(&FOO); } } This will print BOOM, as the initial Boom is swapped out from behind the reference and then dropped.