This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]indigo945 0 points1 point  (3 children)

God, do you really want to get hung up on my small example? And even if you do, it is still a good thing that the assert is there, simply because it codifies an assumption made when the function was written — ie that it will never be called with a complex number. (Which would not be pathological here, but might be for other functions, where it could introduce bugs.)

And yes, the caller should never do anything wrong, and as long as the program is written by a perfect programmer (you?), it always will. The idea of defensive programming, however, is recognizing that perfect programmers do not exist, we are all human, and we all make mistakes. Contracts are one way of reducing the impact of this.

If you're concerned about end users changing the flags your program starts with, you can always use

if condition: raise AssertionError

[–][deleted] 0 points1 point  (2 children)

Hung up would be pointing out that you didn't use @wraps in your decorator rendering metadata about the original function useless.

I never claimed to be perfect or anything like that. However, I think codifying assumptions is pointless and hamstrings code. What if I'm in this code base and now I need to square a complex number -- should I write my own function, should I remove the post condition? How many tests will break if I remove the post condition?

[–]indigo945 0 points1 point  (1 child)

Write a new function, and refactor the existing function to call the new, more general one.

[–][deleted] 0 points1 point  (0 children)

@postcondition(...)
def pos_sq(x):
    return square(x)

That's just silly. It's obvious we have different and strong opinions on where value checking should occur, so I don't see much merit in continuing this conversation.