Errors, 1 of 4
Throw and Catch
Declare what a function throws, throw an error, and handle it with Try, Catch, and Try?.
What you’ll build
A function that reads a port number from a setting, like "8080", and fails clearly when the text
isn’t a usable port. Its callers handle the failure in three ways: catch it, pass it on, or turn it
into a default.
Throws and Throw
A function that can fail lists what it throws after its result type, with Throws. Throw stops
the code where it is with an error: an object of std.core’s Error Class, or of a Class extending
it, made with a message. Unless a Try block around it in the same function catches it, the
error leaves the function.
Import std.core
Function ParsePort(text: String): Int Throws Error
Local port = Int.Parse(text)
If port == Null Then Throw Error("'{text}' isn't a number")
If port < 1 || port > 65535 Then Throw Error("{port} isn't between 1 and 65535")
Return port
End Function
Try
Print(ParsePort("8080"))
Print(ParsePort("http"))
Print("not reached")
Catch e
Print("bad port: {e.Message}")
End Try8080 bad port: 'http' isn't a number
A Try block runs its body, and when something in it throws, the rest of the body is skipped and
the Catch runs with the error. A call that can throw must be inside a Try block, or written
with the Try or Try? prefix, which the next steps show. fb checks this when it compiles, so an
error can’t be forgotten:
Import std.core
Function ParsePort(text: String): Int Throws Error
Local port = Int.Parse(text)
If port == Null Then Throw Error("'{text}' isn't a number")
Return port
End Function
Print(ParsePort("8080")) Compiling port.fb
port.fb:9:7: error: 'ParsePort' can throw Error, so calling it needs Try, Try?, or a Try block
|
9 | Print(ParsePort("8080"))
| ^^^^^^^^^^^^^^^^^
error: couldn't build port.fb because of 1 errorHandling each value
A Try block inside a loop handles each failure and goes on to the next value.
Import std.core
Function ParsePort(text: String): Int Throws Error
Local port = Int.Parse(text)
If port == Null Then Throw Error("'{text}' isn't a number")
If port < 1 || port > 65535 Then Throw Error("{port} isn't between 1 and 65535")
Return port
End Function
For text In ["8080", "http", "70000", "443"]
Try
Print("port {ParsePort(text)}")
Catch e
Print("skipped: {e.Message}")
End Try
End Forport 8080 skipped: 'http' isn't a number skipped: 70000 isn't between 1 and 65535 port 443
Passing an error on
Try before a call lets the call’s errors go on to the caller, which must then declare them with
Throws, or catch them itself. The function stops where the error happened, as it would for a
Throw of its own.
Import std.core
Function ParsePort(text: String): Int Throws Error
Local port = Int.Parse(text)
If port == Null Then Throw Error("'{text}' isn't a number")
Return port
End Function
Function Address(host: String, portText: String): String Throws Error
Local port = Try ParsePort(portText)
Return "{host}:{port}"
End Function
Try
Print(Address("localhost", "8080"))
Print(Address("localhost", "eighty"))
Catch e
Print("bad address: {e.Message}")
End Trylocalhost:8080 bad address: 'eighty' isn't a number
Try?: a default instead
Try? turns a call that throws into a value that can be Null: the call’s result, or Null when
it throws, and the error is dropped. With ??, that gives a default.
Import std.core
Function ParsePort(text: String): Int Throws Error
Local port = Int.Parse(text)
If port == Null Then Throw Error("'{text}' isn't a number")
Return port
End Function
Local port = Try? ParsePort("http") ?? 3000
Print("listening on {port}")listening on 3000
Use Try? when the error’s details don’t matter. When they do, catch it.
Errors no one catches
Top-level code can let an error out. The program then prints uncaught, the error’s Class and
message, where it was thrown, and a stack trace, and exits with code 1.
Import std.core
Function ParsePort(text: String): Int Throws Error
Local port = Int.Parse(text)
If port == Null Then Throw Error("'{text}' isn't a number")
Return port
End Function
Local port = Try ParsePort("http")
Print(port)uncaught Error: 'http' isn't a number at port.fb:5:26
at ParsePort (port.fb:5)
at top-level code (port.fb:9)What you learned
Throwsafter a result type lists what a function can throw, andThrowthrows it.- Every call that can throw needs a
Tryblock, aTryprefix, orTry?. Catch ehandles an error, ande.Messagesays what went wrong.Try callpasses the error on to the caller, whoseThrowsmust cover it.Try? callgivesNullon an error, and??turns that into a default.- An error that leaves top-level code prints where it was thrown, and exits with code 1.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.