Combinators- A functional approach of error handling in ‘Rust’

Reading Time: 3 minutes

In this world, everyone is interested in the spikes whether it is related to professional thing or personal. In this blog, I am going to give you spikes of the programming practices in Rust.

Error Handling – process of handling the possibility of failure

Today, every programmer is worried whether he has implemented error handling in right manner or not. There are various ways to deal with errors in Rust:

  • panic!
  • Option
  • unwrap
  • Result

We will discuss only Option & unwrap rigorously. If you are reading this blog means you already know about Options and how to use them in your code, same follows for unwrap.

Lets have an classic example which you guys prefer normally:

  • Normally you use unwrap() if you are sure that there will be some value or you didn’t care about error handling.
struct Person {
name: String,
age: i32
}

fn display(person : Option<Person>) {
println!("{:?}",person.unwrap());
}

fn main() {
let person = Some(Person {
name: "Amita".to_string(),
age: 16
});

display(person);
}
  • But if you care about the case where you are not going to get the value then you use match to handle error.
struct Person {
    name: String,
    age: i32
}

fn display(person : Option<Person>) {
    match person {
        Some(person) =>println!("{:?}",person),
        None => println!("No person")
    }
}

fn main() {
    let person = Some(Person {
        name: "Amita".to_string(),
        age: 16
    });
    
   display(person);
}

match is a valid method for handling Option. However, you may find tedious to use unwrap() while dealing with operations only valid with an input. Here, combinators can be helpful to you. You can handle error using map() and and_then() ,built-in method of Option.

  • Combinators: map – When you are sure that you are getting some value then you can use map() instead of unwrap(). This is more functional approach and let you chaining the operations performed on it.
struct Person {
    name: String,
    age: i32,
}

fn display(person: Option<Person>) {
    let result: Option<String> = person.map(|p| p.name)
        .filter(|x| x.contains("Ami"))
        .take();
    println!("{:?}", result.unwrap());
}

fn main() {
    let mut person: Option<Person> = Some(Person {
        name: "Amita".to_string(),
        age: 16,
    });

    display(person);
}
  • Combinators: and_then – When you use map() on a function that returns an Option<T> then you will get Option<Option<T>>. Chaining multiple calls together can then become confusing. So now you can use and_then().
#[derive(Debug)]
enum Work { Office, Gym, Market }

#[derive(Debug)]
enum Day { Monday, Tuesday, Wednesday }

fn have_work(work: Work) -> Option<Work> {
    match work {
        Work::Gym => None,
        _ => Some(work),
    }
}

fn work_type(work: Work) -> Option<Work> {
    match work {
        Work::Market => None,
        _ => Some(work),
    }
}

fn workable_v1(work: Work) -> Option<Work> {
    match have_work(work) {
        None => None,
        Some(work) => match work_type(work) {
            None => None,
            Some(work) => Some(work),
        },
    }
}

fn workable_v2(work: Work) -> Option<Work> {
    have_work(work).and_then(work_type)
}

fn find_work(work: Work, day: Day) {
    match workable_v2(work) {
        Some(work) => println!("Yay! On {:?} we get to work on {:?}.", day, work),
        None => println!("Oh no. We don't get to work on {:?}?", day),
    }
}

fn main() {
    let (office, gym, market) = (Work::Office, Work::Gym, Work::Market);

    find_work(office, Day::Monday);
    find_work(gym, Day::Tuesday);
    find_work(market, Day::Wednesday);
}

In the above example, using map() instead of and_then() would have given the Option<Option<Work>>, which is an invalid type for find_work().

I hope that this blog will clear the usage of combinators over unwrap(). Happy Error Handling!!!


Knoldus-blog-footer-image

Written by 

Amita Yadav is a Software Consultant Trainee at Knoldus Software INC, currently working on RUST, system programming language. She is self-determined at what she has to do. She likes to learn trending technologies. She is familiar with languages such as C++, C, Java, Scala and technologies like lagom, Play, Akka, Kafka, spark, and databases like Cassandra, MySql, Sqlite, Slick. She loves to create amazing videos mashup.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading