Coding Topics
-
-
Save victormartins/dccb50608596991cbfbf52142f7b3206 to your computer and use it in GitHub Desktop.
"The Problem is that the part of a program that spots an error isn't always the part that can figure out what to do about it." ... "Exceptions clearly separate normal processing from error processing. This makes programs easier to understand. Understandability is next to godliness." – Refactoring - Ruby Edition
"Decide if the caller should check for the condition before making the call or rescue the exception. If the error is likely to occur in normal processing then I would make the caller check the condition before calling. If the error is not likely to occur, then I would rescue the exception." – Refactoring - Ruby Edition
def withdraw(amount)
raise ArgumentError if amount > @balance
@balance -= amount
end
class Account
include Assertions
def withdraw(amount)
assert!('Amount is to large') { amount <= @balance }
@balance -= amount
end
end
module Assertions
class AssertionFailedError < StandardError; end
def assert(message, &condition)
return if condition.call
raise(AssertionFailedError, "ASSERTION FAILED: #{message}")
end
end
In this case we create a custom exception and let the consumers of the method rescue and handle the error.
class BalanceError < ArgumentError; end
class Account
def withdraw(amount)
raise BalanceError if amount > @balance
@balance -= amount
end
end
class Foo
def some_operation
(...)
account.widthdraw(amount)
(...)
rescue BalanceError => e
handle_balance_error_exception
end
end
Warning: Algorithms that use exception/rescue are many times slower than conditional checking. We probably do this in the validation stuff. Maybe being invalid is exceptional in our case, or maybe not if this is user data.
In this case, use conditionals for code flow and use assertions as we saw above, to raise exceptional errors.
"Exceptions should be used for exceptional behaviour: behaviour that is an unexpected error. They should not act as a substitute for conditional tests. If you can reasonably expect the caller to check the condition before calling the operation, you should provide a method for a given test that returns a boolean, and the caller should use it." – Refactoring - Ruby Edition
def resource
if @available.empty?
@allocated.push(Resource.new)
else
@allocated.push(@available.pop)
end
end
def resource
@allocated.push(@available.pop)
rescue EmptyStackError
@allocated.push(Resource.new)
end