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
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):
Function g returns a value
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
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.
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?
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:
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).
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.
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.
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.
Valid:
julia> f(h(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.
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,
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…)