Computation termination

Hello,

Say I run f(g(x)) where f has no method for a Nothing data type and where g is defined as:

function g(x)
    if condition on x is true
        return a computed valid type for f
    end
end

f, therefore, will throw a method error if the condition isn’t met; is there a way to terminate the computation of g before returning nothing to the caller? something like this

function g(x)
    if condition on x is true
        return a computed valid type for f
    end
    terminate() # without returning `nothing`
end

It sounds like you are looking for exit().

I tried it, but terminates Julia.

As far as I know there are only two possibilities for the behavior of function g (outside of pathological behavior like exiting Julia or making it hang):

  1. Function g returns a value
  2. Function g throws an exception

(Any other behavior doesn’t make sense: if you write y = g(x) and you “terminate g before returning”, what should be the value of y?)

Both options can be good choices… If “condition on x is false” happens when g is called with an invalid value, it makes sense to use an exception (although exceptions are more expensive in terms of performance so sometimes you want to avoid them):

function g(x)
    if condition on x is true
        return a computed valid type for f
    end
    error("Bad value x: ...")
end

function f(x)
    try
        y = g(x)
    catch
        # Do something in bad case
    end
end

Often it is better to let g return Union{Nothing, Float64} or similar:

function g(x)
    if condition on x is true
        return a computed valid type for f
    end
end

function f(x)
    y = g(x)
    if isnothing(y)
        ...
    else
        ...
    end
end
2 Likes

Why is it not possible to define a method for f?

f(x::Nothing) = nothing
1 Like

Throwing an exception indeed does the job; problem is, it seems a hacky solution to me, because – in my case – it is not an exception as such: it prints and ugly Error message and its backtrace (though the backtrace can be supressed). I am looking for a “cleaner” solution without an error message, that can be misleading for users.

Because I’m lazy and want to avoid creating a bunch of methods that seem superfluous.

BTW, this is perhaps what I’ll end up doing – in spite of my laziness.

or at least, is there a way the edit the Error string in the throw function to something less aggressive? say Info

I don’t think so: an uncaught exception is an error. But you can catch the expression with a try block, and then you can print the message you want (or do nothing).

Could you give a full, concrete example of the behavior you want?

1 Like

f(x::Nothing) = nothing is not superfluous, if it is the difference between f(g(x)) being correct code or not. If you do not want the write the definition because it can be abused, and instead treat it at the call site, for many different kinds of single-argument functions, then you can define something like:

allow_nothing(f) = (x -> isnothing(x) ? nothing : f(x))

to use at the places you call the functions. Or you can create a macro alternative that defines a method for you with similar behavior (but without the overhead of a closure) and invoke the macro for all functions (but as this is already single-line, I believe it is basically the same amount of effort).

2 Likes

My case is quite involved, so I’ll formulate something simpler.

I can catch the expression and print something but it still returns nothing, which f receives and throws the method error.

I think that the solution is what you said @sijo: throw an exception. I found a way how to suppress the backtrace that produces a clean output; I only need to figure how to change/suppress the ugly red Error message tag. I looked into the throw code but it’s quite cryptic to me (I’m still sort of a julia neophyte) so I cannot replace that pesky error tag string. At least this solution does what I’m looking for; perhaps I should be content with that.

This elides the red Error word:

Base.showerror(io::IO, e::ResponseException, bt; backtrace=true) = print(io, "\b"^7 * e.msg)

Does the job, but it’s horrid! The signature of a true noob.

I’d love to see a minimal working example of the thing you’re trying to achieve. It doesn’t have to be a real-life example, but some small working code that shows the behavior you want for functions f and g.

Here it goes:

struct MyException <: Exception
    msg::AbstractString
end

function Base.showerror(io::IO, e::MyException, bt; backtrace=true)
    print(io, "\b"^7)
    print(io, e.msg)
end

f(x::Real) = x^2

function h(x)
    if isa(x, Real)
        x
    else
        e = MyException("This is not an error, I just want to terminate execution.")
        throw(e)
    end
end

Now test.

  1. Valid:
julia> f(h(1))
1
  1. Invalid:
julia> f(h("one"))
This is not an error, I just want to terminate execution.

which is what I was looking for: terminate execution to avoid a f’s method error.

return nothing is THE way to terminate execution of a function early.

If you use return nothing for something else, make your own signeton type and return that thing.

1 Like

Indeed, but the whole point is to avoid defining an f(x::Nothing) method.

Am I correct in saying you want something like R’s stop function.
Which terminates execution and returns to the top-level prompt without showing an big scary error message and stacktrace?

We have definitely talked about that before.
At least once,

3 Likes

I don’t know… this actually seems like a good solution for what you’re trying to do. BUT I suspect you’re trying to do something that’s wrong: calling h with a bad x value is an error and it’s wrong to pretend otherwise. If a user calls f1 that calls f2 that calls f3 that calls f and all they get is the message Computation interrupted (this is not an error), they will have a hard time finding the root of the problem.

Or maybe this x is not really a bad value? It’s a valid value that means “interrupt all computations”? I don’t remember seeing a real-life case where this makes sense. It sounds more like a recipe for spaghetti code: you have an inner function call that short-circuits all the caller functions as part of normal program execution (not error)? It’s like a goto but even worse because it’s not explicit.

To stay sane and avoid spaghetti code, when you write f(g(x)) you normally want g to do its own job without interferring with the callers, and f should decide itself if it wants to interrupt its own computation depending on the return value of g (and f can include a try-catch block if it knows that g can throw an exception that f can handle itself).

(Of course maybe your thing actually does make sense and then I’d be curious to understand it better…)