Throwing and trapping errors with Tcl
John PeckPublished
Image by pch.vector on Freepik
I've been trying to be better about throwing errors in my Tcl code for tcladu. There seem to be at least three ways to do this: error, throw, and return. Is there any difference? Here's what I tried:
# Demonstrate handling errors with Tcl
proc iterint {start points} {
# Return a list of increasing integers starting with start with
# length points
set count 0
set intlist [list]
while {$count < $points} {
lappend intlist [expr $start + $count]
incr count
}
return $intlist
}
proc pdict {dict {pattern *}} {
set longest 0
dict for {key -} $dict {
if {[string match $pattern $key]} {
set longest [expr {max($longest, [string length $key])}]
}
}
dict for {key value} [dict filter $dict key $pattern] {
puts [format "%-${longest}s = %s" $key $value]
}
}
proc throw_error { code } {
switch $code {
1 {
set message "This error was thrown with error"
set errorcode "FIRST_ERROR_CODE"
error $message -errorcode $errorcode
}
2 {
set message "This error was thrown with throw"
set errorcode "SECOND_ERROR_CODE"
throw $errorcode $message
}
3 {
set message "This error was thrown with return -code error"
set errorcode "THIRD_ERROR_CODE"
return -code error -errorcode $errorcode $message
}
}
}
foreach code [iterint 1 3] {
puts "-----------------------------------"
try {
throw_error $code
} trap {FIRST_ERROR_CODE} {message optdict} {
puts "Error handler for FIRST_ERROR_CODE"
puts "Message is: $message"
puts "Context:"
pdict $optdict
} trap {SECOND_ERROR_CODE} {message optdict} {
puts "Error handler for SECOND_ERROR_CODE"
puts "Message is: $message"
puts "Context:"
pdict $optdict
} trap {} {message optdict} {
puts "Catch-all error handler"
puts "Message is: $message"
puts "Context:"
pdict $optdict
}
}
puts "-----------------------------------"
...and here's the output:
-----------------------------------
Error handler for FIRST_ERROR_CODE
Message is: This error was thrown with error
Context:
-errorinfo = -errorcode
(procedure "throw_error" line 1)
invoked from within
"throw_error $code"
("try" body line 2)
-errorcode = FIRST_ERROR_CODE
-code = 1
-level = 0
-errorstack = INNER {invokeStk1 throw_error 1}
-errorline = 2
-----------------------------------
Error handler for SECOND_ERROR_CODE
Message is: This error was thrown with throw
Context:
-errorcode = SECOND_ERROR_CODE
-code = 1
-level = 0
-errorstack = INNER {returnImm {This error was thrown with throw} {-errorcode SECOND_ERROR_CODE}} CALL {throw_error 2}
-errorinfo = This error was thrown with throw
while executing
"throw $errorcode $message"
(procedure "throw_error" line 11)
invoked from within
"throw_error $code"
("try" body line 2)
-errorline = 2
-----------------------------------
Catch-all error handler
Message is: This error was thrown with return -code error
Context:
-errorcode = THIRD_ERROR_CODE
-code = 1
-level = 0
-errorstack = INNER {invokeStk1 throw_error 3}
-errorinfo = This error was thrown with return -code error
while executing
"throw_error $code"
("try" body line 2)
-errorline = 2
-----------------------------------
The differences are in the error options dictionary captured by the try
command. The errorstack
key has a much larger value with the throw
command. The various commands otherwise do the same thing.
Links
- Try command official documentation.
- Error handling question on Stack Overflow.
- Throw command official documentation.
- Pretty printing dictionaries in Tcl.