On Nov 1, 6:57 pm, Steven D'Aprano <[EMAIL PROTECTED] cybersource.com.au> wrote: > On Sat, 01 Nov 2008 17:12:33 -0700, Bryan wrote: > > The list of validation error descriptions is returned instead of raising > > exceptions so clients can show the errors to the user for fixing. > > Raising exceptions seems like an uneeded burden for the client, as there > > is nothing exceptional about bad user input. > > But of course there is. Exceptional doesn't mean rare. In this case, it > just means it's not the "normal" input which is expected. > > > Instead, I want to raise an > > exception if a client actually tries to save an invalid entity back to > > the database. I will have to think on your suggestion a bit more before > > I am sure however. > > As a general rule, every function should return one "kind" of thing. > Notice I don't say "type", because it doesn't matter what the type/class > of the data is, so long as it is conceptually the same sort of result. > > E.g. a function that opens a connection to a database should *only* > return a connection to a data, although the actual type of that > connection may differ depending on the database. It shouldn't return > either a connection or an error code. > > I say that this is a general rule, because you can get away with breaking > it, sometimes. E.g. string.find() returns either an offset or an error > signal of -1. But note that this sometimes leads to bugs where people > forget to check for a result of -1, and end up with code doing something > unexpected. > > You've suggested a usage: > > "The list of validation error descriptions is returned instead of > raising exceptions so clients can show the errors to the user for > fixing." > > But you can do that with an exception as well: > > while True: > try: > validate(arguments) # returns None on success, or raise Failure > break > except Failure, e: > print e.msg > for error in e.errors: > print "You must fix this error: %s" % error > # when we exit the loop, the arguments are validated. > do_something_with(arguments) > > If you're coming from a Java background, you may be concerned that > exceptions are expensive. They aren't. Setting up the try...except block > is very cheap. There's very little overhead to a try block that doesn't > fail. > > -- > Steven
I'm coming from a .Net background, and yes, one of the reasons I did not consider raising exceptions was to avoid the overhead of an exception handler clause, which in .Net land is expensive. some more thought on this: If I were going to be checking for validity during a property setter, I would probably raise an exception there, because the essence of what a client was requesting is "set property", and an invalid value precludes this action from happening. However, hoping to make client code cleaner and to avoid setter functions doing expensive db lookup validations, I do not validate during the setter, but instead defer it until the client explicitly asks for the validity of the business object. So the essence of the client's request at that point is "what are the invalid values for the object", and an exception should only be raised if there was something stopping this request from being served. Invalid business object field values do not stop the functionality of the invalid() method. If I had a validation function that checked the db for a duplicate primary key, then the invalid() function should raise an exception if the db could not be contacted. A client should be on the lookout for that type of exception, but to throw a bunch of exceptions back at a client who simply requested a list of things that need to be fixed seems heavy. We would essentially be using Exceptions as an expected return value of a function. So a doc string would explain: "Returns None for a valid object, and Exceptions for an invalid object." Should exceptions be an expected "return value" from a function? Am I still using my .Net brain? Bryan -- http://mail.python.org/mailman/listinfo/python-list