-
-
Save zedshaw/1d89c156c03815dcb5ad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Examples of various error handling mechanisms and if-statements. | |
def something(x,y): | |
if !x: | |
raise "argh!" | |
else: | |
if !y: | |
raise "oh noes!" | |
else: | |
return "Happy" | |
# if those aren't guards/asserts then this | |
def something(x, y): | |
if x and y: | |
return "Happy" | |
else: | |
raise "Oh noes!" | |
# if they are then this: | |
def something(x, y): | |
assert x, "You have a bad x." | |
assert y, "You have a bad y." | |
return "Happy" | |
# If the exception is needed, then use | |
# a real exception, not a string. | |
# chances are you don't actually need | |
# this though and assert works. | |
def something(x, y): | |
if !x: raise BadError("Bad x.") | |
if !y: raise OtherBadError("Bad y.") | |
return "Happy" | |
# If this was a really common pattern, I might do make | |
# a decorator and copy Design by Contract semantics. | |
@precond(x, "You have a bad x.") | |
@precond(y, "You have a bad y.") | |
def something(x, y): | |
return "Happy" | |
# but that's really just replicating asserts | |
# It's more that you are making an assert, and | |
# should treat it as such, not as logic. That way | |
# the logic for operation is easily seen without | |
# being fuzzed by error handling logic. | |
# | |
# The better pattern then is to confirm the | |
# function's parameters are correct to operate | |
# at the beginning, then do your logic for it | |
# working, handling errors as you go, then | |
# confirm your returning the right result | |
# and not violating any invariants you need. | |
# For example, confirming you didn't return | |
# None if that caused errors frequently. | |
# That's all easier done with asserts or a | |
# DbC system. | |
# | |
# Here's a *better* example of what you're | |
# asking: | |
def decider(x, y): | |
assert x and y, "Invalid arguments." | |
if x == "oranges": | |
if y == "grapes": | |
print "You have oranges and grapes." | |
else: | |
raise FruitError("Invalid fruit for y.") | |
elif x == "starfruit": | |
if y == "apples": | |
print "You have starfruit and apples." | |
else: | |
raise FruitError("Invalid fruit for y.") | |
else: | |
raise FruitError("Invalid fruit for x.") | |
# in this case the raised errors in the dangling | |
# else branches ensure that, should the function's | |
# usage change in the future to include other | |
# possible fruit, this will blow up and you'll have | |
# to go fix it for the new situation. It is effectively | |
# a "whitelist if" because you are saying "this only | |
# handles these conditions, everything else is an error." | |
# | |
# The extra advantage of this then is if you do automated | |
# testing you can evolve your code easily by adding the | |
# new fruit to the test for this, run it, and fix wherever | |
# it blows up. Much easier than scanning ever possible | |
# branch, but in more complicated functions you'd still | |
# need to do that. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def something(x,y): | |
if !x: | |
raise "argh!" | |
if !y: | |
raise "oh noes!" | |
return "Happy" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment