Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It also invites exceptions as error handling instead of a monadic (result) pattern. I usually do something more like

    Result<Users> userRes = getExpiredUsers(db);
    if(isError(userRes)) {
        return userRes.error;
    }

    /* This probably wouldn't actually need to return a Result IRL */
    Result<Email> emailRes = generateExpireyEmails(userRes.value);
    if(isError(emailRes)) {
        return emailRes.error;
    }

    Result<SendResult> sendRes = sendEmails(emailRes.value);
    if(isError(sendRes)) {
        return sendRes.error;
    }
    
    return sendRes; // successful value, or just return a Unit type.
This is in my "functional C++" style, but you can write pipe helpers which sort of do the same thing:

    Result<SendResult> result = pipe(getExpiredUsers(db))
        .then(generateExpireyEmails)
        .then(sendEmails)
        .result();

    if(isError(result)) {
        return result.error;
    }
If an error result is returned by any of the functions, it terminates immediately and returns the error there. You can write this in most languages, even imperative/oop languages. In java, they have a built in class called Optional with options to treat null returns as empty:

    Optional.ofNullable(getExpiredUsers(db))
        .map(EmailService::generateExpireyEmails)
        .map(EmailService::sendEmails)
        .orElse(null);
or something close to that, I haven't used java in a couple years.

C++ also added a std::expected type in C++23:

    auto result = some_expected()
        .and_then(another_expected)
        .and_then(third_expected)
        .transform(/* ... some function here, I'm not familiar with the syntax*/);




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: