Comment

Comment by geofft

If you have a language with enum types (Haskell, ML, etc., or any of the languages inspired by them like Rust, Scala, etc.), that's straightforward. In e.g. Rust, you'd have

    enum Connection {
        ValidConnection {fd: RawFd, address: SockAddr, ...},
        BadAddr,
        BadPort,
        ...
    }
In fact Rust's representation of the maybe type is just a generic

    enum Option<T> {
        Some(T),
        None,
    }
so all you're doing is getting rid of the two layer Option<Connection> syntax and making it a single Connection, so you're not writing Option<this>, PossiblyBadAddress<that>, etc. everywhere.

Then all your call sites can do one of two things. Either they can check for specific errors, like

    match conn {
        Connection {fd, address, ..} => write(fd, ...),
        BadAddr => /* handle error */,
        BadPort => /* handle error */,
    }
or you can write a simple function that throws an exception, if you really want an exception-handling style:

    impl Connection {
        fn get_fd(&self) -> RawFd {
            match *self {
                ValidConnection {fd, ..} => fd,
                BadAddr => panic!("The given address was not correct"),
                BadPort => panic!("The given port was not correct"),
            }
        }
    }
and then call conn.get_fd(). For a simple command-line app, panicking and aborting is pretty much what you'd want to do anyway. For a test suite, panics are caught per test case (and you can even test that a function does panic with a given message), so it's very testable.
parent geofft 11 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton