Skip to content
FutureBlitz

    Install

    Errors, 2 of 4

    Error types

    Define error Classes with details of their own, catch each kind apart, and wrap one error in another.

    What you’ll build

    The error handling of a program that loads its settings: a missing setting is one kind of error, a bad value another, and a missing file a third, from the standard library. Each kind carries the details its handler needs, and a Catch for each handles it its own way.

    A Class of your own

    An error type is a Class that extends Error. One without a New of its own takes Error’s, a message and an optional cause. One that adds fields writes a New, which passes the message on with Super.New.

    settings.fb
    Import std.core
    
    Class SettingError Extends Error
    End Class
    
    Class MissingSetting Extends SettingError
        ReadOnly Field Key: String
    
        New(key: String)
            Super.New("'{key}' isn't set")
            Key = key
        End New
    End Class
    
    Function Setting(key: String): String Throws MissingSetting
        If key == "host" Then Return "localhost"
        Throw MissingSetting(key)
    End Function
    
    Try
        Print(Setting("host"))
        Print(Setting("port"))
    Catch e As MissingSetting
        Print("missing {e.Key}: {e.Message}")
    End Try
    Output
    localhost
    missing port: 'port' isn't set

    Catching by Class

    Catch e As T catches errors of Class T, or of a Class that extends it; inside it, e is a T, with its fields. An error goes to the first Catch that matches, so the more specific ones come first. A Catch that an earlier one covers, or that nothing in the body can throw, is an error. Catch e with no Class catches the rest.

    settings.fb
    Import std.core
    
    Class SettingError Extends Error
    End Class
    
    Class MissingSetting Extends SettingError
        ReadOnly Field Key: String
    
        New(key: String)
            Super.New("'{key}' isn't set")
            Key = key
        End New
    End Class
    
    Function Port(settings: String[]): Int Throws SettingError
        If settings.Count == 0 Then Throw MissingSetting("port")
        Local port = Int.Parse(settings[0])
        If port == Null Then Throw SettingError("port '{settings[0]}' isn't a number")
        Return port
    End Function
    
    For settings In [["8080"], [], ["eighty"]]
        Try
            Print("port {Port(settings)}")
        Catch e As MissingSetting
            Print("using the default port, since {e.Key} isn't set")
        Catch e As SettingError
            Print("can't start: {e.Message}")
        End Try
    End For
    Output
    port 8080
    using the default port, since port isn't set
    can't start: port 'eighty' isn't a number

    Throws SettingError covers MissingSetting too, since it extends SettingError.

    The standard library’s errors

    Each area of the standard library has an error type whose Kind, an Enum, says what went wrong. std.io throws an IOError, with kinds such as NOT_FOUND and PERMISSION_DENIED.

    settings.fb
    Import std.core
    Import std.io
    
    Try
        Local text = File.ReadText("settings.ini")
        Print(text)
    Catch e As IOError
        Print(e.Kind)
        If e.Kind == IOErrorKind.NOT_FOUND Then Print("no settings file, so using the defaults")
    End Try
    Output
    NOT_FOUND
    no settings file, so using the defaults

    An error and its cause

    An error can hold the error that led to it, its Cause, so a high-level message keeps the low-level detail. When an error with a cause goes uncaught, the program prints the whole chain, each cause on a caused by line.

    settings.fb
    Import std.core
    Import std.io
    
    Function LoadSettings(): String Throws Error
        Try
            Return File.ReadText("settings.ini")
        Catch e As IOError
            Throw Error("couldn't load the settings", e)
        End Try
    End Function
    
    Local settings = Try LoadSettings()
    Print(settings)
    Output
    uncaught Error: couldn't load the settings at settings.fb:8:9
    caused by IOError: can't read settings.ini: no such file or directory at std/io/request.fb:35:5
        at LoadSettings (settings.fb:8)
        at top-level code (settings.fb:12)

    Each error also has a Place: the file, line, and column it was first thrown from, which the first line of the report shows.

    What you learned

    • An error type is a Class that extends Error, with fields for its details.
    • Catch e As T catches a T or a Class extending it; put the specific ones first.
    • Throws Base covers every Class that extends Base.
    • std’s errors have a Kind Enum, like IOError’s NOT_FOUND.
    • Error(message, cause) wraps an error, and an uncaught one prints its causes.

    Report an issue with this page or with FutureBlitz on GitHub.