Try/Catch shortcut

Clarification:
I’m looking for something similar to: condition ? a : b
Except, my condition is when a returns some type of error, then do b instead of a.

AZ(x)= try; sqrt(x); catch e; return sqrt(complex(x)); end
AZ(2), AZ(-2)

#I want
AZ(a,b)= try; a; catch e; return b; end
AZ(sqrt(-2), sqrt(complex(-2)))

x = try sqrt(-1); catch e; 0 ; end

x is now = 0

I want a function AZ(a,b) which first does a and if there is an error doing a, then does b.

AZ( a, b) = try sqrt(a) catch; sqrt(b) end 
AZ(-1,4)

No such function can ever exist in general because functions evaluate all of their arguments, but you want control flow (like the ternary operator provides), so you need to write a macro. Maybe something like the following:


macro trycatch(a, b)
    quote
        try
            tmp = $(esc(a))
            tmp
        catch
            $(esc(b))
        end
    end
end

let x = 2
    @trycatch(sqrt(x), sqrt(complex(x)))
end

let x = -2
    @trycatch(sqrt(x), sqrt(complex(x)))
end
4 Likes

Thanks! Do you know where a?b:c is in the Julia source code?

Currently I’ve been programming an mle solver where loglik returns -Inf for illegal parameters:

    ll(θ;dist=dist,data=data) = try
        -sum(logpdf.(dist{Float64}(θ...),data))
    catch e
        return Inf
    end

I’d prefer an operator like a?$:
ll(θ;dist=dist,data=data)= -sum(logpdf.(dist{Float64}(θ...),data)) @?$ Inf

What do you mean by that? That’s part of Julia’s syntax: it’s in the parser and isn’t a function whose definition you could read. You could write a macro to reuse that syntax for your own needs if you wanted to.

4 Likes

Also this might be interesting

tryesce(a, b) =
    for i in b 
        tmp = nothing 
        try
            tmp = a(i)
        catch
        end
        tmp === nothing ? continue : return tmp  
    end

tryesce(sqrt, [-1,-2,4])

To followup w/ the above example (which works great!):

macro trycatch(a, b)
    quote
        try
            tmp = $(esc(a))
            tmp
        catch
            $(esc(b))
        end
    end
end
#
f1(x)=@trycatch(sqrt(x), sqrt(complex(x)))
f1(2), f1(-2)

is it possible to rewrite: @trycatch(f(x), g(x))
with my own @$@ as follows: f(x) @$@ g(x)
I wasn’t able to find this in the macro docs.

No, there’s no such thing as infix macros in Julia, unfortunately.

2 Likes

But then how do they allow: cond ? a : b same as ifelse(cond,a,b)?

They are not the same thing:

julia> true ? println("foo") : println("bar")
foo

julia> ifelse(true, println("foo"), println("bar"))
foo
bar
1 Like

Also note that the ternary operator is a language feature, not a macro. Therefore, it also can’t be redefined by the user.

3 Likes

So bottom line if I have some function:
add(a,b) I cannot rewrite it as a @$@ b

Functions are very different from macros. You can redefine infix operators, because they are just generic functions. Functions can’t transform syntax though. For example, you can define the infix operator $:

julia> a $ b = 10 * a + b
$ (generic function with 1 method)

julia> 1 $ 2
12
2 Likes

I think you’re getting fixated on macro being an infix operator, which isn’t possible but shouldn’t matter that much. You can easily do something like @t a $ b.

3 Likes