I should note, that sealed traits are also a good solution to the problem of private trait bounds in public interfaces.
Consider this public function:
pub fn function<T: PrivateBound>(arg: T) { /* do something */ }
Such functions are prohibited currently, because PrivateBound
is a “private trait in a public interface”. However, desire to write such functions was expressed by various people (here and here).
Private bounds can be used to emulate function overloading: instead of
pub fn function(arg: f32) {}
pub fn function(arg: f64) {}
pub fn function(arg: my_f16) {}
the author provides one generic function
pub fn function<T: MyFloat>(arg: T) {}
where MyFloat
denotes the closed set of types {f32
, f64
, my_f16
} and the author doesn’t want users to extend this set.
However, look at this function from user’s perspective - function
is a function that can accept what, MyFloat
? What is MyFloat
? Something private and undocumented. Do I have to read the source code to understand what arguments can function
accept? Should the author write some informal documentation next to function
about what MyFloat
represent?
This situation is suboptimal. The trait MyFloat
should be public and documented. The user should be able to write wrapper functions around function
and use MyFloat
as a bound. I’m not sure if the user should be able to use MyFloat
's methods. Finally, the user shouldn’t be able to implement MyFloat
because the function
's author wants the overload set to be closed and controlled by him. The whole setup reminds sealed traits a lot.