Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Result

An Optional says that there is no answer. Often the caller also needs to know why, and that is outcome.Result( of T, E ): a T on success, or an E that explains the failure.

#import "std/outcome"

'' A port number, or the reason the text is not one.
type PortResult as outcome.Result( of int32, ustring )

function ParsePort( byref text as ustring ) as PortResult
    if len( text ) = 0 then
        return outcome.Fail( of int32, ustring )( "the port is empty" )
    end if
    if str( valint( text ) ) <> text then
        var why = "'" & text & "' is not a number"
        return outcome.Fail( of int32, ustring )( why )
    end if
    var port = valint( text )
    if port < 1 orelse port > 65535 then
        var why = text & " is outside 1 to 65535"
        return outcome.Fail( of int32, ustring )( why )
    end if
    return outcome.Ok( of int32, ustring )( port )
end function

dim inputs( 0 to 3 ) as ustring = { "8080", "http", "70000", "" }
for each text in inputs
    var r = ParsePort( text )
    if r.IsOk( ) then
        print "port"; r.Value( )
    else
        print "refused: "; r.Failure( )
    end if
next

'' ValueOr picks a default; a new Result is a failure.
print "or the default:"; ParsePort( "x" ).ValueOr( 80 )
dim unset as PortResult
print "a new Result is ok: "; unset.IsOk( )

Output

port 8080
refused: 'http' is not a number
refused: 70000 is outside 1 to 65535
refused: the port is empty
or the default: 80
a new Result is ok: false
Procedure or memberDoes
outcome.Ok( of T, E )( v )a success holding v
outcome.Fail( of T, E )( why )a failure holding why
r.IsOk( )whether it succeeded
r.Value( )the value; a runtime error if it failed
r.Failure( )the reason; a runtime error if it succeeded
r.ValueOr( d )the value, or d on failure

Ok and Fail each take only one of T and E as a parameter, so the compiler cannot infer the other, and both type arguments are always written. That is why the result type is named once, with type PortResult as outcome.Result( of int32, ustring ), and the long spelling appears only where a value is built.

A new Result is a failure. dim unset as PortResult reports IsOk( ) false. Code that forgets to set a Result cannot claim success by accident. Because both slots always exist, T and E must each be a type that can be created with no arguments.

Within that rule E can be any type. A ustring is enough to tell a person what went wrong; a type with a code field lets a program branch on the reason.

Activities

  1. Give ParsePort a fourth failure: a port below 1024 is "reserved".
  2. Replace the ustring failure with a type PortError holding an enum code and a message, and print a different line for each code.