I am calling a function fit_circle that may or may not call the MESSAGE procedure. fit_circle calls a function poly_fit that may call the MESSAGE procedure, but also occasionaly produces a math error (there is nothing I can do about this).
Is it possible to contruct an error handler that will take care of all of these scenarios without returning to the interactive prompt? I have tried the following:
FUNCTION arb_funct,circular_data
CATCH, ERROR
IF ERROR NE 0 THEN BEGIN
CATCH, /CANCEL
print, 'An Error Occured'
return, []
ENDIF
circle_fit_result = fit_circle(circular_data)
return, circle_fit_result
END
However the error handler never triggers. The documentation only seems to mention looking for error handlers defined in procedures.
Works for me. Here is my example code:
pro mg_error_demo_helper2
compile_opt strictarr
a = b
end
pro mg_error_demo_helper1
compile_opt strictarr
mg_error_demo_helper2
end
pro mg_error_demo
compile_opt strictarr
catch, error
if (error ne 0L) then begin
catch, /cancel
print, 'An error occurred'
return
endif
mg_error_demo_helper1
end
When I run it, I get:
IDL> mg_error_demo
% Compiled module: MG_ERROR_DEMO.
error happened
IDL has three different types of "catchable" errors:
"Normal" Errors: These are the most common type of error to handle. They are thrown when message is called. Use catch or on_error to deal with them.
IO Errors: These happen when a conversion, disk read, memory, or other "IO" error occurs. Usually, these will also be caught by catch and on_error. When they aren't, use on_ioerror to deal with them.
Math Errors: These happen when you divide by 0, do certain math with NaN or infinity, etc. Deal with them using check_math and !except.
Here's an example of using all three in one program:
function arb_funct, circular_data
; handle normal errors
catch, error
if error ne 0 then begin
catch, /cancel
print, 'A normal error occured: ' + !error_state.msg
return, []
endif
; handle IO errors
on_ioerror, arb_funct__ioerror
if 0B then begin
arb_funct__ioerror:
print, 'An IO error occured: ' + !error_state.msg
return, []
endif
; clear math errors from previous routines
math_err = check_math(/print)
previous_except = !except
!except = 0
; do stuff
circle_fit_result = fit_circle(circular_data)
; handle math errors
math_err = check_math()
!except = previous_except
if math_err ne 0 then begin
print, 'A math error occured: ' + strtrim(math_err, 1)
return, []
endif
; and finally return
return, circle_fit_result
end
Here is an example of to what I referred:
FUNCTION some_function
;;--------------------------------------------------------------------------
;; Error handling [put towards beginning of routine]
;;--------------------------------------------------------------------------
CATCH, error_status
IF (error_status NE 0) THEN BEGIN
;; Cancel error handler
CATCH, /CANCEL
;; Print error message
PRINT, 'Error index: ', error_status
PRINT, 'Error message: ', !ERROR_STATE.MSG
;; Define return variable or how to handle error
;; --> I usually use a formatted output consistent with the expected
;; output, but here I will just use 0 for example.
dumb = 0
;; Return defined variable
RETURN,dumb
ENDIF
;;--------------------------------------------------------------------------
;; Main body of routine
;;--------------------------------------------------------------------------
blah = 0
; blah
; blah
; blah
;;--------------------------------------------------------------------------
;; Return to user
;;--------------------------------------------------------------------------
RETURN,return_variable
END
Hope that helps...
Related
Zig's documentation shows different methods of error handling including bubbling the error value up the call stack, catching the error and using a default value, panicking, etc.
I'm trying to figure out how to retry functions which provide error values.
For example, in the below snippet from ziglearn, is there a way to retry the nextLine function in the event that a user enters greater than 100 characters?
fn nextLine(reader: anytype, buffer: []u8) !?[]const u8 {
var line = (try reader.readUntilDelimiterOrEof(
buffer,
'\n',
)) orelse return null;
// trim annoying windows-only carriage return character
if (#import("builtin").os.tag == .windows) {
return std.mem.trimRight(u8, line, "\r");
} else {
return line;
}
}
test "read until next line" {
const stdout = std.io.getStdOut();
const stdin = std.io.getStdIn();
try stdout.writeAll(
\\ Enter your name:
);
var buffer: [100]u8 = undefined;
const input = (try nextLine(stdin.reader(), &buffer)).?;
try stdout.writer().print(
"Your name is: \"{s}\"\n",
.{input},
);
}
This should do what you want.
const input = while (true) {
const x = nextLine(stdin.reader(), &buffer) catch continue;
break x;
} else unreachable; // (see comment) fallback value could be an empty string maybe?
To break it down:
instead of try, you can use catch to do something in the case of an error, and we're restarting the loop in this case.
while loops can also be used as expressions and you can break from them with a value. they also need an else branch, in case the loop ends without breaking away from it. in our case this is impossible since we're going to loop forever until nextLine suceeds, but if we had another exit condition (like a limit on the number of retries), then we would need to provide a "fallback" value, instead of unreachable.
You can also make it a one-liner:
const input = while (true) break nextLine(stdin.reader(), &buffer) catch continue else unreachable;
Hopefully the new self-hosted compiler will be able to pick up on the fact that the else branch is not necessary, since we're going to either break with a value loop forever.
Suppose I'm using a package function f that takes a single argument x and performs some error checking on that argument. Like, is x of the right type? Etc. And if there is an error then f(x) throws an error with Error().
Is there an easy way to write a wrapper function fCatch around f to catch that error, and say return false if f(x) throws an error but true otherwise? The naïve way to accomplish this same effect would be to copy the code for f and change all the Error(...); lines into a return false; and set a return true; at the end, but it's bad form to duplicate all the error-checking code.
As per Alexander Konovalov's comment, the following works, except the Error(...) message that f(x) triggers still prints.
fCatch := function(x)
local result;
BreakOnError := false;
result := CALL_WITH_CATCH(f, [ x ])[1];;
BreakOnError := true;
return result;
end;
A warning: the CALL_WITH_CATCH function, and any other function with an ALL CAPS name, is undocumented and intended to only be used internally in GAP.
Consider the following try/catch flow
function test(x)
try x^3
if x < 0; error("i only accept x >= 0"); end
return x^3
catch
return abs(x)^3
end
end
How can I display the error message (and stack trace) in the case test(-2) # == 8? In this case I know the error, but if it's a more complicated function with asserts etc, I'd like to know what specifically failed.
Trying rethrow() needs to be done in the try-catch block, but I still want a return value.
You can save the Exception into a variable after writing the variable name of your choice right after catch. error creates an ErrorException. You can see the fields of this Exception using fieldnames(ErrorException). The msg field gives you the message you passed to error. Alternatively, you may use showerror method.
function test(x)
try x^3
if x < 0; error("i only accept x >= 0"); end
return x^3
catch e
showerror(stdout, e)
# or
println(e.msg)
end
end
For the stack trace, you may use stacktrace(catch_backtrace()). We pass catch_backtrace to stacktrace, because what we usually want is to obtain the stack trace of the context of the most recent exception and not the current context.
I have a 'while' loop as part of an OVM test that looks like this:
while (signal_val == 0) begin
signal_val = sla_vpi_get_value_by_name ("blah");
end
I want to restrict this loop for 120 microseconds only and exit after that. I want to quit the test if (signal_val == 0) is still not being satisfied at the end of 120µs. How do I achieve this?
I figured I'll have to call the 'global_stop_request()' to quit from the test, but trying to check the existing condition in the while loop for a fixed timeout value (120µs) seems to be tricky. Also, 'break' does not seem to be working. Any ideas?
Tried using 'break' this way, but 'break' gives a syntax error:
while (signal_val == 0) begin
signal_val = sla_vpi_get_value_by_name ("blah");
#120us;
break;
end
Your code won't work as you are expecting. Let us take a look:
while (signal_val == 0) begin
signal_val = sla_vpi_get_value_by_name ("blah");
#120us;
break;
end
signal_val is evaluated initially just once at the while statement, and since it is 0, you enter the while loop
signal_val gets the value returned by your function call. This happens at the same simulation cycle as the previous evaluation of while. Assuming that there is no change, you get 0 as the return value again
Now, the function waits 120us
Finally, it breaks out of while loop. signal_val isn't evaluated again.
To achieve the functionality you want, you would need to use fork...join and a watchdog task
fork
begin: wait_signal_val
while (signal_val == 0) begin
signal_val = sla_vpi_get_value_by_name ("blah");
if (signal_val == 1) begin
`uvm_info(get_name(), "YES!! signal_val was seen as 1", UVM_LOW);
end
else begin
#20ns; // (or some clocking mechanism)
end
end
end
begin: watchdog
#120us;
`uvm_fatal(get_name(), "NOPE!! signal_val is still 0 after 120us. Killing test");
end
join_any
disable fork
In the above code, either watchdog or wait_signal_val finishes. When that happens, the fork...join_any completes and disables the fork.
I use this a lot in my testbench for functionality like you describe and it works seamlessly.
I would like to do logic like:
local function create(...)
for k, v in ipairs{...} do
if k == "player" then
_player = v
end
end
if _player == nil then
**error**("It nil") -- stop running here and throw the error
end
end
Does Lua has anything like error function here?
Yes, there is, and its name is exactly error():
if _player == nil then
error("It nil") -- stop running here and throw the error
end
error() takes a string argument for error message and an optional argument for level, it terminates the program when called.