5 ms·
> disable the move trait entirely and provide a utility function for move-like creation. There's no way to disable moving in general. But there is the Pin trai
by oconnor663 7y ago
> disable the move trait entirely and provide a utility function for move-like creation.
There's no way to disable moving in general. But there is the Pin trait, which prevents you from moving certain types in certain cases, mostly to do with async/await.
- pornel 7y agoThe Pin type is a mess IMHO. It's the most C++-like corner of Rust. Its guarantees are shallow, so non-trivial uses are still unsafe. It ended up having complex interactions with other language features, creating a soundness hole. I'd rather bury it as a necessary evil that was required to ship async/await syntax, and nothing more.
- oconnor663 7y agoIt's certainly tricky to think about, when I start reading all the docs. (Someone just recently explained what "Pin projection" is to me, and I realized I hadn't really understood Pin before that.) But at the same time, it seems to mostly accomplish its goal of "you don't have to think about this in safe code." Is there a better way we could've solved the same problems? I kind of feel the same way about Send and Sync. Like, why are there two thread safety traits? What could it possibly mean to be Sync but not Send? But at the end of the day, that's what's necessary to model the problem, and I've gotten used to it.
- wging 7y agoTry https://users.rust-lang.org/t/sync-but-not-send/21551/3 https://users.rust-lang.org/t/sync-but-not-send/21551/3?
- withoutboats 7y agoI don't want to be defensive but this is completely off base, and very disheartening to see you post. Allowing users to write safe self-referential code was never a design goal of Pin - only to make it safe to manipulate self-referential objects generated by the compiler, which it has succeeded at. The incredibly overblown soundness hole had far more to do with the quirks of #[fundamental] than Pin (and the soundness hole is being resolved without changing the Pin APIs at all or breaking any user code). The guarantees of Pin are now even being used beyond self-referential types but also for intrusive data structures in tokio's concurrency primitives. Pin is not for everyday users, but it is one of the greatest success stories of Rust's unsafe system. That you would call it a mess to a forum of non-users is quite disspiriting.
- pornel 7y agoSorry, I should have phrased that in a kinder way. The fact that Pin is expected to enable more than it does is part of the problem. It's not for usual self-referential structs. It's not for usual umovable types. It has 2000 words of documentation, and I'm still not sure what to do with it. I need to understand pin/unpin, structural/non-structural projections, and drop guarantees. It has a lot of "you can do this, but then you can't do that" rules that the compiler can't help with. For me most Rust features are either easy to understand (like UnsafeCell or MaybeUninit), or I can rely on the compiler make me use them correctly (like borrowing or generics). But with Pin my impression is that it pushes the limits of what can be done without compiler's safety net.
- leshow 7y agoReally? I have almost the exact opposite opinion of it. If anything Pin validated the construction of Rust the language and it's approach to structuring types in the standard library. We got to express something at the type level without implementing it as some kind of custom language feature. It's complicated, but it's describing a complicated problem so the complexity is inherent. And luckily, most users will never have to interact with Pin anyway.
- quietbritishjim 7y agoThanks for the clarification! I suppose there are two interpretations of "move" in general: (1) the object is now owned by a different variable, potentially with a different lifetime; (2) the footprint of the object is now in a different location in memory. It seems that std::pin refers to the second one: > A Pin<P> ensures that the pointee of any pointer type P has a stable location in memory, meaning it cannot be moved elsewhere and its memory cannot be deallocated until it gets dropped. We say that the pointee is "pinned". That is actually the definition of "move" that I had meant, after all that is what is bad for an object that points into its own footprint. But I realise that "move" in Rust normally means the first one (but note that even Rust's own documentation uses "move" the other way in that snippet above!).
- withoutboats 7y agoYour post suggests a bit of confusion about the meaning of "lifetime" in Rust - a confusion which is common and why we are somewhat unhappy with how that terminology has played out. Variables don't have a "lifetime," references do. When we talk about lifetimes we talk about the lifetime of references to variables, during which time the variable cannot be moved, dropped, etc. The "lifetime of the variable must be greater than the lifetime of the reference" is a common mental model but this lifetime of the variable doesn't really come into play in reality. Your 1) and 2) always coincide in the abstract model, though the compiler may optimize out memcpys that have no impact. When you move a pointer around, you don't move the object it points to.
- oconnor663 7y agoWhat's the more precise term for a variable's "lifetime"? Its "scope"?
- quietbritishjim 7y agoAh OK. What word would you use to describe the period starting where the variable is assigned to and ending when it is dropped or moved-from?
- 7y ago