Julia equivalent of purrr::safely in R?

Hi again,

I’m looking to see if anyone has already created a library like purrr in R, which offers the excellent functionality of safely. For anyone unfamiliar, safely is awesome for capturing side effects. It’s like try-catch, but more convenient. In other words, it yields an object containing both a result and an error. If error is populated then you know whatever you were trying to do failed, and if not then whatever you were doing succeeded. You simply check to see if error is null/not-null and handle however you please (push a notification, write to a log, etc.).

I’ve used this for wrapping httr API calls, or for wrapping joins, …pretty much everything.

Is there anything like this for side effect handling in Julia?

Thank you in advance!

1 Like

Something like this?

julia> function safely(f)
       x=try
       f()
       catch ex
       return nothing, ex
       end
       return x,nothing
       end
safely (generic function with 1 method)

julia> f() = 4
f (generic function with 1 method)

julia> g() = error("not 4")
g (generic function with 1 method)

julia> safely(f)
(4, nothing)

julia> safely(g)
(nothing, ErrorException("not 4"))
3 Likes

Yep, almost exactly like that. Except, the purrr::safely package allows us to wrap other functions in a generalized way. E.g., I could do something like safe_fromJSON = purrr::safely(jsonlite::fromJSON) or safe_GET = purrr::safely(httr::GET). Then I could use, say, safe_GET in-place of httr::GET. E.g., httr::GET(get_URL) vs safe_GET(get_URL)

Does this make sense? Ideas on how to modify the function you shared to achieve this? Thanks for the rapid response, @ggggggggg

This seems to work. I don’t have a good sense of the downsides to this approach, but there are probably some.

julia> safewrap(f) = (x...) -> safely(()->f(x...))
safewrap (generic function with 1 method)

julia> z(x,y) = x+y
z (generic function with 1 method)

julia> Z=safewrap(z)
#11 (generic function with 1 method)

julia> Z(3,4)
(7, nothing)

julia> Z(3,3)
(6, nothing)

julia> Z(3)
(nothing, MethodError(z, (3,), 0x00000000000063f3))
1 Like

try catch seems barely more verbose and much clearer

1 Like

@bramtayl I see your point, but I really appreciate convenience functions like the one @ggggggggg shared.

@ggggggggg Here’s what I’m trying to do: I have a join which fails spectacularly (crashes the Julia REPL), and I want to wrap it in such a way that failure of the join doesn’t kill the running Julia process. I have both the safely function you describe, and safewrap but the following code doesn’t work:

safe_join = safewrap(join)
safe_join(submission_df, submission_query_df, on = [:audience, :subdomain, :reddit_date])

The error is “function #43 doesn’t accept keyword arguments”.

I really appreciate your help trying to crack this nut as I stumble through learning Julia (after years in R/tidyverse)

I think that investigating the cause of this would be the best way to solve your problem.

If it actually crashes the Julia process, a try ... catch block is unlikely to help you.

You may want to try Debugger.jl to find out when/why it crashes.

3 Likes

Try

safewrap(f) = (args...; kwargs...) -> safely(() -> f(args...; kwargs...))

instead.

3 Likes