Rust: Hide Cow implementation details

Created on 5 Aug 2020  路  9Comments  路  Source: rust-lang/rust

Cow is implemented with implementation details, can we add additional layers on top of it to allows other Cow ripoffs such as https://github.com/maciejhirsz/beef to easily become a Cow drop-in replacement without changing anything?

Currently, Cow is accessed through the fields directly, we could add additional methods to access those fields and soft deprecate the existing direct access to the enum fields. Any thoughts on this?

The bad side of this is it may reduce some ergonomic use of structural match for Cow. Moved from https://github.com/rust-lang/wg-allocators/issues/67

T-libs

Most helpful comment

Std Cow is good enough. Just like std String, which some people want small string optimization.
Maybe document that there are alternatives on crates.io (but don't mention specifically one)
may have better performance than std's Cow.
However currently that's seem to be a trade-off between ergonomics and perf.
Cow is low usage in the wild. Also anyone cares about extreme performance should measure that
Cow is a bottleneck.

All 9 comments

Currently Rust has no way to change publicity of enum variants.
And changing publicity of Cow variants is a breaking change.

I am not saying changing publicity of Cow variants, I am just saying soft deprecate it (still usable) in favor of function rather than enum variants to hide implementation details, so it should only just emit a warning, breaking change can be done during editions.

Even though beef may be more efficient, it does not have the ergonomic of structural match (match cow) and also not being able to be a drop-in replacement for the Cow in standard library because of the usage of enum.

Std Cow is good enough. Just like std String, which some people want small string optimization.
Maybe document that there are alternatives on crates.io (but don't mention specifically one)
may have better performance than std's Cow.
However currently that's seem to be a trade-off between ergonomics and perf.
Cow is low usage in the wild. Also anyone cares about extreme performance should measure that
Cow is a bottleneck.

There are quite a few drop-in replacement for standard library. For example, hashbrown (merged), parking-lot, crossbeam, dashmap, async-std. They mainly exists because of the performance/ergonomics for the stuff in standard library could be improved. However, beef is not as straightforward and could not be a drop-in replacement because of the public API exposed for Cow, which is an enum is hard to be replaced by a drop-in replacement.

Unlike hashbrown and other crates you mentioned, Cow has low usage in the wild.
Many cases I see that one could use it (in returned position) but they've just used Owned value for simplicity.

We could reduce Cow memory usage like beef::Cow by teach rustc to leverage padding field for enum tagging.
It could be a win for Result enum cases too.
However I don't know how complicated it is. That's a question for compiler team.
Also does it make guaranteeing Rust ABI of Cow (maybe Result) harder? Some people/groups cares about that.

And beef crate is not general enough to replace Cow in all use cases: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=669acd1af17520f835cdbf09dfe5e4b8

error[E0277]: the trait bound `Foo<'_>: beef::traits::internal::Beef` is not satisfied
  --> src/main.rs:43:20
   |
43 |     dbg!(size_of::<beef::Cow<'_, Foo>>());
   |                    ^^^^^^^^^^^^^^^^^^ the trait `beef::traits::internal::Beef` is not implemented for `Foo<'_>`
   |
  ::: /home/lzutao/.cargo/registry/src/github.com-1ecc6299db9ec823/beef-0.4.4/src/generic.rs:22:23
   |
22 | pub struct Cow<'a, T: Beef + ?Sized + 'a, U: Capacity> {
   |                       ---- required by this bound in `beef::generic::Cow`

We could reduce Cow memory usage like beef::Cow by teach rustc to leverage padding field for enum tagging.

This is not achievable I believe, because padding can be written to freely by codegen.

Also unsafe code and MaybeUninit types.

padding can be written to freely by codegen

Isn't that only struct padding? It seems like enum padding used to normalize the size of variants is different and must be retained in general (since it's only padding for some variants, and contains data in others). Which means that it should be possible to use as a niche.

(previously very briefly discussed at https://github.com/rust-lang/rust/issues/46213#issuecomment-394388912)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nikomatsakis picture nikomatsakis  路  340Comments

GuillaumeGomez picture GuillaumeGomez  路  300Comments

withoutboats picture withoutboats  路  308Comments

withoutboats picture withoutboats  路  211Comments

nikomatsakis picture nikomatsakis  路  268Comments