Sunday, 27 November 2022

Try Expressions

I've recently found that Kotlin supports try-catch-finally expressions (in the same vein as switch expressions). They seem particularly useful to me when executing a block that will assign to a variable or assign a default if the block fails, like this:



fun main (args: Array) {
  val str="23"
  val a: Int? = try { str. toInt () } catch (e: NumberFormatException) {-1}
  println (a)
}


I think this is the first time I see this feature in a programming language, and as usual I've been thinking about how to simulate it, in this case in JavaScript. We can easily simulate the try-catch expression with a tryFn function (emulating try-catch-finally would be more complicated).



function tryFn(fn, exceptions, onErrorFn){
    try{
        return fn();
    }
    catch (error){
        if (exceptions.some(exception => error instanceof exception)){
            return onErrorFn(error)
        }
        else{
            throw error;
        }
    }
}

//val = tryCatch(fn1, [Error1, Error2], onErrorDefaultFn)


We can use this function like this:



class InvalidUrlError extends Error{}
class InvalidPostError extends Error{}
class InvalidUserError extends Error{}


function getPost(url, postId, user){
    if (!url)
        throw new InvalidUrlError("Wrong URL")
    if (!postId)
        throw new InvalidPostError("Wrong Post")
    if (!user)
        throw new InvalidUserError("Wrong User")
    return `Post ${postId} by {user} content`;
}

function formatPost(post){
    return `[[[${post}]]]`;
}

let infos = [
    ["server.org", "1", "xuan"],
    [null, "1", "xuan"],
    ["server.org", null, "xuan"],
    //["server.org", "2", null],
    ["server.org", "3", "xuan"]
]


for (let info of infos){
    let post = tryFn(() => formatPost(getPost(...info)),
        /*catch*/ [InvalidUrlError, InvalidPostError], (ex) => {
            console.log(`caught error: ${ex.constructor.name}`);
            return "No Post"
        } 
    );
    console.log(`post: ${post}`)
}


Well, not sure I will ever use it, but I think it's a valid attempt.

This reminds me a bit of cases where combining await and .catch() for async code rather than wrapping the async call in a try-catch makes the code cleaner. I'm talking about this

No comments:

Post a Comment