Errors, 4 of 4
Panics and stack traces
Stop the program on a bug with Assert and Panic, and read the stack trace that points at it.
What you’ll build
A function that averages groups of numbers and states its assumptions with Assert. When a caller
breaks one, the program stops, and its stack trace leads from the failed check back to the call
that caused it.
Panics are for bugs
A panic stops the program at once. It prints panic:, a message, and where it happened, then a
stack trace, and exits with code 101. The language panics on its own for bugs it can see: an index
out of range, a missing Map key, integer overflow in a debug build, and dividing an integer by
zero.
Import std.core
Function Share(total: Int, people: Int): Int => total / people
Print(Share(100, 4))
Print(Share(100, 0))25
panic: division by zero at divide.fb:3:49
at Share (divide.fb:3)
at top-level code (divide.fb:6)A panic can’t be caught, and it doesn’t run Defer statements or Finally blocks: the program’s state is wrong, so nothing more of it runs.
Assert
Assert(condition, message) panics with the message when the condition is false. It states what
a function counts on, so a broken assumption stops the program where it’s broken, instead of
causing a wrong answer later. The message is only made when the check fails.
Import std.core
Import std.collections
Function Average(values: Int[]): Int
Assert(values.Count > 0, "Average needs at least one value")
Local sum = 0
For value In values
sum += value
End For
Return sum / values.Count
End Function
Function Report(groups: Int[][]): String
Local averages: String[] = []
For group In groups
averages.Add("{Average(group)}")
End For
Return averages.Join(", ")
End Function
Print(Report([[1, 2, 3], [10, 20]]))
Print(Report([[4], []]))2, 15
panic: Average needs at least one value at average.fb:5:5
at Average (average.fb:5)
at Report (average.fb:16)
at top-level code (average.fb:22)The trace lists the calls the panic happened in, the innermost first, each with its file and line:
at Average (average.fb:5)is the failedAssert, inAverage.at Report (average.fb:16)is the line ofReportthat calledAverage.at top-level code (average.fb:22)is the line of the program that calledReport.
The bug isn’t in Average, which checked its input as it should, but in the call at line 22,
which passed an empty group. Every build has stack traces, debug and release alike, with no
debug files to ship.
Panic, Unreachable, and Todo
Panic(message) panics outright, for a state the program should never be in. Unreachable()
marks code that can’t be reached, and Todo(message) code still to be written. Each ends its
path, so a function that returns a value can end with one.
Import std.core
Function Sign(n: Int): String
If n > 0 Then Return "positive"
If n < 0 Then Return "negative"
If n == 0 Then Return "zero"
Unreachable()
End Function
Function Describe(value: Float): String
Todo("describe Floats")
End Function
Print(Sign(-3))
Print(Describe(1.5))negative
panic: this isn't done yet: describe Floats at sign.fb:11:5
at Describe (sign.fb:11)
at top-level code (sign.fb:15)Errors or panics
Throw an error for a failure that a correct program must expect, and that a caller can do
something about: bad input, a missing file, a network that’s down. Panic, usually through
Assert, for a mistake in the program itself, which only changing the code can fix. Here a
person’s typing can be wrong, so ParseAge throws; but Percent is only ever called with a
whole above 0 by correct code, so it asserts.
Import std.core
Function ParseAge(text: String): Int Throws Error
Local age = Int.Parse(text)
If age == Null || age < 0 Then Throw Error("'{text}' isn't an age")
Return age
End Function
Function Percent(part: Int, whole: Int): Int
Assert(whole > 0, "Percent needs a whole above 0")
Return part * 100 / whole
End Function
Local ages: Int[] = []
For text In ["34", "old", "61"]
Try
ages.Add(ParseAge(text))
Catch e
Print("please try again: {e.Message}")
End Try
End For
Local over40 = 0
For age In ages
If age > 40 Then over40++
End For
Print("{Percent(over40, ages.Count)}% are over 40")
Print("{Percent(over40, 0)}%")please try again: 'old' isn't an age
50% are over 40
panic: Percent needs a whole above 0 at ages.fb:10:5
at Percent (ages.fb:10)
at top-level code (ages.fb:27)The bad input is reported and the program goes on; the bad call stops it.
What you learned
- A panic stops the program with a message, a place, and a stack trace, and exits with code 101.
- Indexes out of range, missing Map keys, integer division by zero, and, in a debug build, integer overflow panic on their own.
Assert(condition, message)panics when an assumption is broken.- A stack trace lists the calls, innermost first, each with its file and line.
Panic,Unreachable(), andTodo()end a path on purpose.- Errors are for failures to expect; panics are for bugs.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.