-
Notifications
You must be signed in to change notification settings - Fork 211
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 for timer traits #86
Comments
Regarding question 3: In the other thread, I proposed a set of traits that allow us to catch errors at compile-time. Those won't work in practice, as it's impossible to use the traits without knowing about the implementation, making them useless. I plan to experiment with this idea some more (no timeline yet). |
Re 1) Yes I would say so, e.g. because it already has been started. |
Another question:
|
Re 4: I'm in favor of the combined approach |
Re 1 and 2: I agree with @therealprof, but I think my assessment of importance is flopped. Either way, it's an argument for a combined approach for those error enums as well -- applications need to be able to distinguish the core "logical" errors from implementation-specific ones. Overall, it seems like this is a step towards forcing applications to use more explicit error handling. While this is a good thing, it could be good to add some additional trait functions with generic implementations that return the "inner" error type (ignoring "generic" errors). Something like: pub trait CountDown {
type Time;
type Error;
fn start<T>(&mut self, count: T) -> std::Result<(), CountDownError<Self::Error>>
where
T: Into<Self::Time>;
fn force_start<T>(&mut self, count: T) -> std::Result<(), Self::Error>
where
T: Into<Self::Time>;
{
match self.start(count) {
Ok(()) => Ok(()),
Err(CountDownError::AlreadyStarted) => Ok(()),
Err(CountDownError::Other(e)) => Err(e),
}
}
}
pub enum CountDownError<T> {
AlreadyStarted,
Other(T),
} (disclaimer: haven't tried compiling the above, I'm just providing it as a brief example. I also haven't thought through the function name to any deep degree) |
Regarding the error handling discussion I would make an argument for error types instead of generic traits: You cannot compose errors if you define them as traits. To make this clear - here is an example a colleague of mine was facing, while trying to write an abstraction for a hardware display (it's not the original code, but a stripped down version): // We have a display and some items like a SPI, that is defined by the traits from the embedded_hal library
impl<SPI, CS> Display<SPI, CS>
where
SPI: Transfer<u8> + Write<u8>,
CS: OutputPin,
{
pub(crate) fn write(spi: &mut SPI, cs: &mut CS, command: Command) -> Result<(), DisplayError> {
if cs.set_low().is_err() {
/* error handling here */
return DisplayError::CSErr;
}
if spi.write(&command.as_byte_array()).is_err() {
/* error handling here */
return DisplayError::SPIErr;
}
Ok(())
}
} So we have a function, that does two things - set some pin and do something with the spi. Both operations can fail and return an Error. What you usually do in this case (FYI: I am not an embedded programmer, maybe I am missing something why you use these traits, I just want to share my perspective), is to implement the pub(crate) fn write(spi: &mut SPI, cs: &mut CS, command: Command) -> Result<(), DisplayError> {
cs.set_low()?;
spi.write(&command.as_byte_array())?;
Ok(())
} Looks way cleaner. However, I cannot do this, if std::io::Error::new(std::io::ErrorKind::Other, "Something unexpected happened"); So I am not bound to any limitations of the pre-defined error type, while still having one well defined type to work with |
@dsxmachina If you are not interested in the contents of the errors, however they look should not matter much in your case. pub(crate) fn write(spi: &mut SPI, cs: &mut CS, command: Command) -> Result<(), DisplayError> {
cs.set_low().map_err(|_| DisplayError::Cs)?;
spi.write(&command.as_byte_array()).map_err(|_| DisplayError::Spi)?;
Ok(())
} Anyway this issue is specifically about errors returned by timers, not error handling in general. That was discussed at length over at #229. PS: remember to set |
Okay, thank you for the info - haven't found the other Issue (might have just searched for open ones). My point was the exact same as therealprof was making in the mentioned issue - I will take a look at the 1.0.0-alpha-0.8 where the changes are merged. P.S: Thanks :) - but as I said, it's a very stripped down version of the original code. Just wanted to show you what I mean. |
Pull request #67 adds a
cancel
method that returns aResult
. We ended up discussing timer error handling in general there, but decided to move further discussion to a follow-up issue (this one).I think we need to find answers to the following questions:
cc @therealprof @jonas-schievink
The text was updated successfully, but these errors were encountered: