How to design ReactiveX error handling in Rust?

Recently, I'm implementing ReactiveX Extensions by Rust, named rx_rs. And now it can do some easy work now. I'm confusing in which is a better way to provide error handling API.

For a simple example:

let numbers = Subject::new();

let odd = numbers.clone().map(|i| {
  // in this closure, you may want throw an error.
}).subscribe(
  |v| println!("{} ", *v),
  |ec: &ErrComplete<()>| {
    // process Error or Complete here.
  })

numbers.next(1);

In operator like map, some error may occur, and user want to throw an exception, and will be processed by error callback registered in subscribe. There are two ways in my mind right now.

First way, just panic

...
let odd = numbers.clone().map(|i| {
  // some logic code ...
  panic!("Network occur!");
}) ...

In this way, this panic will be captured by panic::catch_unwind, and the error handling closure will be called.

Second way, every operator should return a Result type.

let odd = numbers.clone().map(|i| {
  // some logic code ...
  Err("Network occur!");
}) ...

In this way, when an operator return a Err, error handling closure for this stream will be call. It's maybe boring, every operator returned type will be wrapped with Result. Like a filter operator never return an error, must be return Ok(bool), can't direct return bool. And how if the operator return type really is an error type, not because an error occur ? Will be confused, must return OK(Err(_)).

So, does panic::catch_unwind is the right way, or anyone has any ideas about it?

1 Like

You should note that panic!() does not always unwind. If the binary is compiled with panic = abort flag, panic!() aborts the whole process and catch_unwind become meaningless.

Rule of thumb is: do not use panic!() for error handling.

1 Like

Propagating runtime errors (such as network errors) via Result is the right way.

panic!() is supposed to be only for signalling bugs that the programmer has to fix (things that documentation says are not allowed, but the program did them anyway, such as reading index out of bounds).

1 Like

Thanks, I never use catch_unwind before.

thanks, I know now, panic is a wrong way, and find a more elegant way via Result.

Thanks guys, I have some ideas for error handling. Each operator will provide two method. Take filter as an example:

One named filter_with_err, this version can propagate runtime errors by return an error, second named filter just return a bool type.

surprise, I also do something similar 2 week ago rxrust, it has a little bit more extensions like fold, flat_map, schedulers, basically work but lack of documents, if you interested in.

of course, may be we should work in a same repo. More extensions is not most important in this moment, we should resolve the framework problems first.

your error issue is something a flat map works for, just flat an error observable, so I'm not sure why extension isn't important in this case
it could be done like

obs.and_then(|x| {
  if (x == 2) { factory::from_value(x) }
  else { factory::throw(Err("Something wrong here")) }
})

Nice, I'll learn your code later. It's important, but at this moment is a very early period for rx_rs. It's more important to define an easy use api, and provide an almost zero cost abstractions.

I try to provide a way for all extension can throw error, and can be capture. Not just flat map.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.