-
-
Notifications
You must be signed in to change notification settings - Fork 435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error handling of distributions::Uniform::new #1195
Comments
Follow up change: |
I agree that this should be done now or never, and IMO it's better to have a breaking change now than have this be an inconsistency in the API forever. If the error type exposes the distinction between I propose avoiding that hullabaloo by returning an opaque error type. The type's debug output can include details about the exact error encountered, which would be as informative to a debugging developer as the current assert approach; if it's ever decided in the future that users actually do need to distinguish these cases programmatically, an accessor could be added in a backward-compatible manner in the style of |
When using |
@kazcw Unfortunately, we have to make the error type public if we want to allow other crates to add support for their types to I'm not sure how often that is used in practice, but removing this option would be a regression. |
- This is a breaking change. - The new error type had to be made public, otherwise `Uniform` could not be extended for user-defined types by implementing `UniformSampler`. - `rand_distr` was updated accordingly. - Also forbid unsafe code for crates where none is used. Fixes rust-random#1195, rust-random#1211.
- This is a breaking change. - The new error type had to be made public, otherwise `Uniform` could not be extended for user-defined types by implementing `UniformSampler`. - `rand_distr` was updated accordingly. - Also forbid unsafe code for crates where none is used. Fixes rust-random#1195, rust-random#1211.
The solution does not need to preclude other crates from implementing The plan is to make pub trait UniformSampler {
// The possible errors vary for different types, and we cannot anticipate the classes of errors
// for all implementors of the trait, so this is an associated type.
type Error: Display;
fn new<B1, B2>(low: B1, high: B2) -> Result<Self, Self::Error>;
// ...
}
impl<X: SampleUniform> Uniform<X> {
fn new<B1, B2>(low: B1, high: B2) -> Result<Self, X::Error> { ... }
// ...
}
pub struct InvalidFloatRange(FloatRangeError);
enum FloatRangeError {
Empty,
Infinite,
}
impl Display for FloatRangeError {
// ...
}
// In the macro defining floating point samplers:
impl UniformSampler for UniformFloat<$Ty> {
type Error = FloatRangeError;
// ...
}
pub struct EmptyRange;
// In the macro defining integer samplers:
impl UniformSampler for UniformInt<$Ty> {
type Error = EmptyRange;
// ...
} So, the question is whether, in a case like
My point earlier was, if we go with (2), we should have a consistent and well-documented precedence of errors when multiple failures are possible; but i can't picture much need for programmatic inspection of the error here, and (1) would be easier. |
I agree with @kazcw that we likely don't need to programmatically expose error details. But, in this case, why have an associated We could do the following, or store pub struct Error {
#[cfg(debug_assertions)]
cause: &'static str,
}
impl Error {
pub fn new(cause: &'static str) -> Self {
#[cfg(not(debug_assertions))] {
let _ = cause;
}
Error {
#[cfg(debug_assertions)]
cause,
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[cfg(debug_assertions)] {
write!(f, "invalid range: {}", self.cause)
}
#[cfg(not(debug_assertions))] {
write!(f, "invalid range")
}
}
} |
* Forbid unsafe code in crates without unsafe code This helps tools like `cargo geiger`. * Make `Uniform` constructors return a result - This is a breaking change. - The new error type had to be made public, otherwise `Uniform` could not be extended for user-defined types by implementing `UniformSampler`. - `rand_distr` was updated accordingly. - Also forbid unsafe code for crates where none is used. Fixes #1195, #1211. * Address review feedback * Make `sample_single` return a `Result` * Fix benchmarks * Small fixes * Update src/distributions/uniform.rs
Currently,
Uniform::new
will panic on invalid parameters:low >= high
(or>
fornew_inclusive
)low
orhigh
scale = high - low
Since #581 / #770, all other distributions with fallible constructor return a
Result
instead of panic (I think).For: consistency and utility (error checking in derived types)
Against: this is another significant breaking change, when we hope to be getting close to stable (though now is certainly better than later)
Alternative:
try_new
,try_new_inclusive
constructors - but this is inconsistent and results in far too many methods.Also related:
Rng::gen_range
uses this. This should probably still panic on failure (note alsoRng::fill
vsRng::try_fill
;Rng::gen_bool
andRng::gen_ratio
which may panic).I suggest this error type:
Link: #1165
The text was updated successfully, but these errors were encountered: