Maybe we should use unsafe trait to “enforce” this property? That’s what I have realized in my own code — I can use unsafe traits when I want to ensure that a user can’t mess up my assumptions by implementing the trait for their external types. Usually it’s a completely hypothetical scenario, yet legal in safe rust and thus I’m “liable”.
Idea: use unsafe trait for UnsignedInt, SignedInt because the traits are effectively closed: no more implementations should be added. This increases their utility: You know only the right types implement it.
I’d go the other direction and get rid of the “a built-in” part of that description. There’s no reason a user shouldn’t be able to implement a u128, BigUnsignedInt, etc.
Unsafe isn’t really the way to go here. One way to fix this is to allow public traits to depend on private traits:
trait Private { }
pub trait Public: Private { }
To avoid putting trait Private { } statements everywhere, rust could implicitly define DefinedInCrate and DefinedInModule traits on a per crate/module basis and implement them on all types defined in acrate/module. However, this system is a little less flexible. However, those would effectively be path-dependent types and I don’t know if rust really wants those.
There are two choices here: AcceptableType is a regular, open trait, and users may usefully impl it for their own types sometimes. The other simpler choice is to make it a closed/private trait.
The closed/private trait is simpler: less public API surface area. I can change the AcceptableType’s methods when refactoring my library. All I used the trait for was for user-facing constructor overload anyway.
Using unsafe trait is not even a solution there – the public trait adds methods to the types it is implemented for. I don’t want that with a closed trait, I don’t want that just because the trait is part of the public API, that its internals and its methods are available to library users. I want that to be an encapsulated detail in my API. All I wanted was overloading of new_from.
The integer traits were built for: Have functions on primitives, allow minimal genericity over primitives.
No code “assumes” properties of these. Nothing breaks if you try to use them on things they weren’t made for. They’re just bad at doing “general” numbers. I don’t see a reason to try to actively prevent people from using a mediocre trait for their BigInt or whatever.
Ok but then the description of the trait is wrong. And I know that numerics in libstd is explicitly not for generalizing over number types, so I was assuming all along it was what it says, a trait for built-in unsigned integer types.