0

I'm exploring Functional programming in Rust. I've been reading that language provides an Error handler with the help of the Result type.

But when using functions, it might end up in runtime errors. Is there any way to specify that a function might have side effects?

Having this code as a reference:

fn map(self, func: fn(T) -> T) -> TryMonad<T>{
     match func(self.success.unwrap())   {
        Ok(v) => TryMonad { success: Some(v), failure:None},
        Err(error) => TryMonad { success: None, failure:Some(error)},
    }
}

Where func might throw an error.

Shall I consider if that happens it will be an unrecoverable panic error?

paleonix
  • 2,293
  • 1
  • 13
  • 29
paul
  • 12,873
  • 23
  • 91
  • 153
  • 3
    It sounds like you're approaching this from a very C++ perspective. Rust doesn't "throw" errors. `throw` isn't even a keyword in Rust. There are two ways to communicate errors in Rust: one is `Result` (as you've already found), and the other is panicking, from which there is no recovery. If a function doesn't return `Result`, then that function can only fail irrecoverably. There's no middle ground. – Silvio Mayolo Apr 23 '23 at 23:01
  • 3
    @SilvioMayolo Nit: there is [recovering](https://doc.rust-lang.org/stable/std/panic/fn.catch_unwind.html) from panics, and the mechanism is the same as for C++ exceptions (including the fact that it might not be available on all platforms/if you want to compile with `fno-exceptions`) — this doesn't change the fact that you wouldn't panic in Rust where you throw in C++. – Caesar Apr 23 '23 at 23:19
  • Does [this answer](https://stackoverflow.com/questions/30505639/how-to-do-error-handling-in-rust-and-what-are-the-common-pitfalls) your question? It's probably not an identical question but it does go into the differences between panicing and returning `Result` – harmic Apr 24 '23 at 02:03
  • Thanks, I got the idea about no runtime errors, and I like it! – paul Apr 24 '23 at 07:07

1 Answers1

2

Well, the problem here is that self.success.unwrap() panics when the variable is None. From the perspective of functional programming, the better approach is pattern matching:

fn map(self, func: fn(T) -> T) -> TryMonad<T> {
    match self {
        | TryMonad { success, failure: None } =>
            TryMonad { success: success.map(func), failure: None },
        | failed @ _ => failed, // return as is
    }
}

On error, we return self as is. Otherwise, we proceed with Some(f(v)).

xamgore
  • 1,723
  • 1
  • 15
  • 30