Custom Errors in Crystal
# A custom error type usually has the suffix "Error".
class ArgError < Exception
getter arg : Int32
getter message : String
def initialize(@arg : Int32, @message : String)
end
# Adding this to_s method makes ArgError implement
# the Exception interface.
def to_s(io : IO) : Nil
io << "#{@arg} - #{@message}"
end
end
def f(arg : Int32) : {Int32, Exception?}
if arg == 42
# Return our custom error.
return {-1, ArgError.new(arg, "can't work with it")}
end
{arg + 3, nil}
end
# Crystal doesn't have a direct equivalent to Go's errors.As,
# but we can achieve similar functionality using is_a?
_, err = f(42)
if err.is_a?(ArgError)
puts err.arg
puts err.message
else
puts "err doesn't match ArgError"
end
This Crystal code demonstrates how to create and use custom error types. Here’s a breakdown of the translation:
We define a custom
ArgError
class that inherits fromException
. This is equivalent to implementing theerror
interface in the original code.The
ArgError
class hasarg
andmessage
properties, similar to the struct in the original code.We implement a
to_s
method, which is Crystal’s equivalent of theError()
method in the original code.The
f
function is translated almost directly, but we use Crystal’s tuple syntax to return multiple values.In the
main
function equivalent, we use Crystal’sis_a?
method to check if the error is an instance ofArgError
. This is similar to theerrors.As
functionality in the original code.
To run this program:
$ crystal run custom_errors.cr
42
can't work with it
Crystal’s error handling is somewhat different from Go’s. It uses exceptions rather than returning error values. However, this example demonstrates how to create a custom error type and use it in a way that’s similar to the Go code.
Crystal doesn’t have a direct equivalent to Go’s errors.As
function, but the is_a?
method provides similar functionality for type checking and casting.