While browsing the source for RefCell the other day, I noticed the following definition:
pub struct BorrowError {
_private: (),
}
This type is returned when we try to borrow a RefCell's contents with try_borrow and friends. It would be nice if we could declare this as pub struct BorrowError;, so that instances could be created without initializing the dummy field. However, this declaration makes BorrowError publicly constructible by struct literal syntax, so adding fields is a breaking change that requires a major version bump.
I would go so far as to call this feature a footgun, since developers might not realize that by writing struct Zst;, which is the most natural way to define such a struct, they’ve committed to a layout of the type unintentionally.
Possible solutions:
- Mention this pattern in the Book. A quick glance reveals that there isn’t an explanation of this problem. (Though I don’t know that the book talks about semantic versioning at all? I could be wrong on all counts.)
- Make
pub struct Zst; not allow for construction outside of the current module, and make it opt-in with pub struct Zst(pub);. This is a breaking change, though churn should be minor since I don’t expect this to be a commonly used feature. I’m not sure what the best lint-then-remove path is, though…
- Reverse the above, with an opt-out mechanism:
pub struct Zst(priv);. While this avoid breakage, I really don’t think the use of the priv keyword is appropriate unless it’s adopted in other places, like enum variants.