3 ms·
Not to detract from the author's work - it does express the concept in "plain English" as promised - but boy oh boy is Pinning a confusing concept. This is com
by 2bitencryption 5y ago
Not to detract from the author's work - it does express the concept in "plain English" as promised - but boy oh boy is Pinning a confusing concept. This is coming from someone who has used rust pretty regularly since 2015.
Sure, in simplest terms, I get it - "Pinning is used to guarantee something is never moved", and the utility of this is mostly (exclusively?) for guarantees in concurrency.
The moment I see the symbol "!Unpin" my brain goes into a fog. "Pinning means things cannot be moved... but most things are Unpin... which can be unpinned after being pinned... but some things are !Unpin... so they can NOT be UN-pinned... so when they are Pinnned they are REALLY pinned..."
It seems to me like "Pin" is a perfectly sound, logical concept, but it was designed by type-system-science nerds, that barely translates to the promise of Rust which is to empower everyone, not just type-system-science nerds, to make safe software.
- vvanders 5y agoI would largely agree, in the cases where I've needed something pinned I just drop to Box'ing to, keeping the box internal and managing the pinning directly. It's annoying because you lose some classes of things that you may want to pin(values on stack for short durations) but I found similar complexities in the API. For instance if you take a pinned Arc(ex: Pin<Arc<T>>) there wasn't a way I could determine to get out the mutable interior pointer(ex: via Arc::get_mut) since those APIs require a specific signature and you would need to un-pin the value to make those calls despite them being by reference(safe from a pinning perspective). Most of Rust is incredibly well designed but so it's pretty jarring that Pinning is so much harder to use. I've found work-arounds for the cases where I've needed either via boxing or dropping to unsafe but would have been nice if it had worked for my use cases.
- cbarrick 5y ago> safe from a pinning perspective The reason you can't get &mut T from Pin<Arc<T>> is because the mutable reference lets you move the data in safe Rust, e.g. with std::mem::swap. So getting the &mut T from a Pin<Arc<T>> is not safe from a pinning perspective.
- vvanders 5y agoFair, but feels like that significantly reduces the utility of pinned types then if for certain values you lose the ability to mutate values when the compiler overwise knows that there is a single mutable reference.
- Tamschi 5y agoThere's a hole or oversight in `Arc`'s API in this regard, annoyingly. The function you're looking for would be something like pub fn get_mut_pinned(this: &mut Pin<Arc<T>>) -> Option<Pin<&mut T>> , which for pinning-aware values should give you enough mutability and for `T: Unpin` can give you `Option<&mut T>` through `Option::as_deref_mut`. Unfortunately, I haven't seen any `Arc` implementations that actually provide it, since almost none of the third-party ones are pinning-aware. (My `tiptoe::Arc`'s `get_mut` has this signature, but that's a specialty container with additional requirements for the contained value.) The same goes for `make_mut_pinned`, that's missing too (but to be fair would be much less useful, since pinning and `Clone` don't often mix that well).
- zozbot234 5y agoHave you tried proposing these API's on the internals.rust-lang.org forum or via posting a proposed RFC? It's not clear to me if they're sound in the general case, but if that's the case they can absolutely be added.
- Tamschi 5y agoI should. I'm not too familiar with the process so far, but I'll find some time for it. These functions are indeed generally sound (also for `Rc`), as any value that cares would be `!Unpin`, which would still bar access to `&mut T`. `make_mut_pinned` also shouldn't cause too much confusion, as availability of `Clone` would have to be declared explicitly just about everywhere that's relevant. They can be implemented as very thin wrappers around their non-pinning equivalents, with only a few `unsafe` operations to make the types fit.