Condition signals and restarts, resumable exceptions (was: Comparison with False - something I don't understand)
* 2010-12-06 00:14 (-0800), Paul Rubin wrote: > You know, I've heard the story from language designers several times > over, that they tried putting resumable exceptions into their > languages and it turned out to be a big mess, so they went to > termination exceptions that fixed the issue. Are there any languages > out there with resumable exceptions? As some people have pointer out Common Lisp is one of those languages. I don't know anything about language design, I'm just a hobbyist programmer, but I think Common Lisp's condition system and its restarts are straight-forward and easy to understand from programmer's point of view. Here's the relevant chapter in Peter Seibel's Practical Common Lisp: http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
"OKB (not okblacke)" writes: > This is an interesting setup, but I'm not sure I see why you need > it. If you know that, in a particular context, you want toy(x, 0) to > result in 42 instead of ZeroDivisionError, ... and that's the point. You don't know whether you'll need it at the call site. Something further up has decided that, in its context, 42 shall be the magic value returned. In some other context, there shouldn't be a magic value, and the exception should terminate the program. My toy example was just that: a minimal example showing the machinery in action. The value of separating out exception handling like this is only apparent if there's a fair amount of code in between the policy (`return 42') and the site where the exception is signalled. Small examples of powerful abstractions aren't very convincing: a small example trivially doesn't require powerful abstraction. Sorry. -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Mark Wooding wrote: > Any code called from within the `with handler' context will (unless > overridden) cause a call `toy(x, 0)' to return 42. Even if the `with > handler' block calls other functions and so on. Note also that the > expression of this is dynamically further from where the error is > signalled than the resume point (which is within the same function). > You can't do this with `try' ... `except'. Which was, of course, the > point. This is an interesting setup, but I'm not sure I see why you need it. If you know that, in a particular context, you want toy(x, 0) to result in 42 instead of ZeroDivisionError, why not just define safeToy(x, y): try: retVal = toy(x, y) except ZeroDivisionError: retVal = 42 return retVal . . . and then call safeToy instead of toy in those contexts? -- --OKB (not okblacke) Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Mon, 06 Dec 2010 08:32:18 -0500, Mel wrote: > Apparently, at the end of his research, Alan Turing was trying out the idea > of 'oracles', where a computable process would have access to an > uncomputable process to get particular results. I would imagine that the > idea here was to clarify what this would do to the computable process. If > he had lived, I doubt that Turing would have built an oracle, but the idea > does live on in interactive debuggers. The "oracle" concept was introduced quite early on in Turing's work, late 1930s. The idea is to examine the complexity of problems relative to other problems. E.g. if you have a Turing machine with access to an oracle which can solve some NP-complete problem, you can analyse the complexity of solving other NP-complete problems in that context. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Carl Banks writes: > On Dec 6, 12:58 pm, m...@distorted.org.uk (Mark Wooding) wrote: > > def toy(x, y): > > r = restart('use-value') > > with r: > > if y == 0: > > error(ZeroDivisionError()) > > r.result = x/y > > return r.result > > > > def example(): > > def zd(exc): > > if not isinstance(exc, ZeroDivisionError): > > return > > r = find_restart('use-value') > > if not r: return > > r.invoke(42) > > print toy(5, 2) > > with handler(zd): > > print toy(1, 0) > > You could do that. > > Or, you could just put your try...finally inside a loop. [You correct `finally' to `except' in a follow-up.] I think you've missed the point almost entirely. Any code called from within the `with handler' context will (unless overridden) cause a call `toy(x, 0)' to return 42. Even if the `with handler' block calls other functions and so on. Note also that the expression of this is dynamically further from where the error is signalled than the resume point (which is within the same function). You can't do this with `try' ... `except'. Which was, of course, the point. -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Dec 6, 2:42 pm, Carl Banks wrote: > Or, you could just put your try...finally inside a loop. er, try...except Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Dec 6, 12:58 pm, m...@distorted.org.uk (Mark Wooding) wrote: > Paul Rubin writes: > > You know, I've heard the story from language designers several times > > over, that they tried putting resumable exceptions into their languages > > and it turned out to be a big mess, so they went to termination > > exceptions that fixed the issue. > > That seems very surprising to me. > > > Are there any languages out there with resumable exceptions? > > Common Lisp and Smalltalk spring to mind. It's fairly straightforward > to write one in Scheme. (Actually, implementing the Common Lisp one in > terms of fluids, closures and blocks isn't especially difficult.) > > > Escaping to a debugger doesn't really count as that. > > Indeed not. > > > I guess one way to do it would be call a coroutine to handle the > > exception, and either continue or unwind after the continue returns, > > but doing it in a single-threaded system just seems full of hazards. > > It seems pretty straightforward to me. Handlers are simply closures; > the registered handlers are part of the prevailing dynamic context. > When an exception occurs, you invoke the handlers, most-recently > registered first. A handler that returns normally can be thought of as > `declining' to handle the exception; a handler that explicitly transfers > control elsewhere can be thought of as having handled it. > > To make this work, all you need is: > > * a fluid list (i.e., one which is part of the dynamic context) of > handlers, which you can build in pure Python if you try hard enough > (see below); > > * closures to represent handlers, which Python has already, and; > > * a nonlocal transfer mechanism, and a mechanism like try ... finally > to allow functions to clean up if they're unwound. > > We can actually come up with a nonlocal transfer if we try, by abusing > exceptions. > > [The code in this article is lightly tested, but probably contains > stupid bugs. Be careful.] > > class block (object): > """ > Context manager for escapable blocks. > > Write > > with block() as escape: > ... > > Invoking the `escape' function causes the context body to exit > immediately. Invoking the `escape' function outside of the > block's dynamic context raises a ValueError. > """ > def __init__(me): > me._tag = None > def _escape(me, value = None): > if me._tag is None: > raise ValueError, 'defunct block' > me.result = value > raise me._tag > def __enter__(me, value = None): > if me._tag: > raise ValueError, 'block already active' > me._tag = type('block tag', (BaseException,), {}) > me.result = value > return me._escape > def __exit__(me, ty, val, tb): > tag, me._tag = me._tag, None > return ty is tag > > This is somewhat brittle, since some intervening context might capture > the custom exception we're using, but I don't think we can do > significantly better. > > Implementing fluids badly is easy. Effectively what we'd do to bind a > fluid dynamically is > > try: > old, fluid = fluid, new > ... > finally: > fluid = old > > but this is visible in other threads. The following will do the job in > a multithreaded environment. > > import threading as T > import weakref as W > > class FluidBinding (object): > """Context object for fluid bindings.""" > def __init__(me, fluid, value): > me.fluid = fluid > me.value = value > def __enter__(me): > me.fluid._bind(me.value) > def __exit__(me, ty, val, tb): > me.fluid._unbind() > > class Fluid (object): > """ > Represents a fluid variable, i.e., one whose binding respects > the dynamic context rather than the lexical context. > > Read and write the Fluid through the `value' property. > > The global value is shared by all threads. To dynamically > bind the fluid, use the context manager `binding': > > with myfluid.binding(NEWVALUE): > ... > > The binding is visible in functions called MAP within the > context body, but not in other threads. > """ > > _TLS = T.local() > _UNBOUND = ['fluid unbound'] > _OMIT = ['fluid omitted'] > > def __init__(me, value = _UNBOUND): > """ > Iinitialze a fluid, optionally setting the global value. > """ > me._value = value > > @property > def value(me): > """ > Return the current value of the fluid. > > Raises AttributeError if the fluid is currently unbound.
Re: Comparison with False - something I don't understand
Paul Rubin writes: > You know, I've heard the story from language designers several times > over, that they tried putting resumable exceptions into their languages > and it turned out to be a big mess, so they went to termination > exceptions that fixed the issue. That seems very surprising to me. > Are there any languages out there with resumable exceptions? Common Lisp and Smalltalk spring to mind. It's fairly straightforward to write one in Scheme. (Actually, implementing the Common Lisp one in terms of fluids, closures and blocks isn't especially difficult.) > Escaping to a debugger doesn't really count as that. Indeed not. > I guess one way to do it would be call a coroutine to handle the > exception, and either continue or unwind after the continue returns, > but doing it in a single-threaded system just seems full of hazards. It seems pretty straightforward to me. Handlers are simply closures; the registered handlers are part of the prevailing dynamic context. When an exception occurs, you invoke the handlers, most-recently registered first. A handler that returns normally can be thought of as `declining' to handle the exception; a handler that explicitly transfers control elsewhere can be thought of as having handled it. To make this work, all you need is: * a fluid list (i.e., one which is part of the dynamic context) of handlers, which you can build in pure Python if you try hard enough (see below); * closures to represent handlers, which Python has already, and; * a nonlocal transfer mechanism, and a mechanism like try ... finally to allow functions to clean up if they're unwound. We can actually come up with a nonlocal transfer if we try, by abusing exceptions. [The code in this article is lightly tested, but probably contains stupid bugs. Be careful.] class block (object): """ Context manager for escapable blocks. Write with block() as escape: ... Invoking the `escape' function causes the context body to exit immediately. Invoking the `escape' function outside of the block's dynamic context raises a ValueError. """ def __init__(me): me._tag = None def _escape(me, value = None): if me._tag is None: raise ValueError, 'defunct block' me.result = value raise me._tag def __enter__(me, value = None): if me._tag: raise ValueError, 'block already active' me._tag = type('block tag', (BaseException,), {}) me.result = value return me._escape def __exit__(me, ty, val, tb): tag, me._tag = me._tag, None return ty is tag This is somewhat brittle, since some intervening context might capture the custom exception we're using, but I don't think we can do significantly better. Implementing fluids badly is easy. Effectively what we'd do to bind a fluid dynamically is try: old, fluid = fluid, new ... finally: fluid = old but this is visible in other threads. The following will do the job in a multithreaded environment. import threading as T import weakref as W class FluidBinding (object): """Context object for fluid bindings.""" def __init__(me, fluid, value): me.fluid = fluid me.value = value def __enter__(me): me.fluid._bind(me.value) def __exit__(me, ty, val, tb): me.fluid._unbind() class Fluid (object): """ Represents a fluid variable, i.e., one whose binding respects the dynamic context rather than the lexical context. Read and write the Fluid through the `value' property. The global value is shared by all threads. To dynamically bind the fluid, use the context manager `binding': with myfluid.binding(NEWVALUE): ... The binding is visible in functions called MAP within the context body, but not in other threads. """ _TLS = T.local() _UNBOUND = ['fluid unbound'] _OMIT = ['fluid omitted'] def __init__(me, value = _UNBOUND): """ Iinitialze a fluid, optionally setting the global value. """ me._value = value @property def value(me): """ Return the current value of the fluid. Raises AttributeError if the fluid is currently unbound. """ try: value, _ = me._TLS.map[me] except (AttributeError, KeyError): value = me._value if value == me._UNBOUND: raise AttributeError, 'unbound fluid' return value @value.setter def v
Resumable exceptions bad: (was Re: Comparison with False - something I don't understand)
On 12/6/2010 12:40 AM, Steve Holden wrote: On 12/6/2010 9:14 AM, Paul Rubin wrote: m...@distorted.org.uk (Mark Wooding) writes: The most obvious improvement is resumable exceptions. You know, I've heard the story from language designers several times over, that they tried putting resumable exceptions into their languages and it turned out to be a big mess, so they went to termination exceptions that fixed the issue. Are there any languages out there with resumable exceptions? Escaping to a debugger doesn't really count as that. I guess one way to do it would be call a coroutine to handle the exception, and either continue or unwind after the continue returns, but doing it in a single-threaded system just seems full of hazards. I seem to remember PL/1 has resumable exceptions, but I don't ever remember finding a real use for them. And it's so long since I used PL/1 I may be mistaken. Resumable exceptions were a popular idea in the early days of programming. LISP, PL/I, and early COBOL had constructs which could be considered resumable exceptions. They didn't work out well, because the exception handler gets control in an ambiguous situation, perhaps in the middle of an expression. Changing the state of the execution, then returning, can leave the program in an invalid state. Signal handling has many of the same problems. A POSIX signal is a forced subroutine call while something else is going on, which is in itself a weird concept. That's what a resumable exception looks like. CPython has a terrible time with signal handling. See "http://www.dabeaz.com/python/UnderstandingGIL.pdf"; for the whole ugly mess. That's why control-C won't terminate multi-thread programs, among other things. Unwinding cleanly from a signal is difficult, but possible with proper CPU and compiler design. It's done right in Ada, and in Visual C++ for x86 on Windows. Only some CPUs support "exact" floating point exceptions, where you're guaranteed that the exception comes in at the point where the problem occurred. In modern superscalar CPUs, the exception comes in several instructions after the problem was detected. In x86 type CPUs, the CPU hardware in the "retirement unit" backs up the CPU state to the point at which the exception was detected. PowerPC and SPARC CPUs do not do this; if you need exactness in exception position on them, you have to put in "fence" instructions to stop lookahead. This costs performance. As a result, C code which unwinds from signals via "longjmp" is not portable. See "https://www.securecoding.cert.org/confluence/display/seccode/SIG32-C.+Do+not+call+longjmp%28%29+from+inside+a+signal+handler"; Nor is changing the program state from inside a signal handler. You're not entirely sure, on many CPUs, where control is at the point the signal came in. (In a physics simulator, I once had to handle floating point overflow, which indicated that the computation had to be backed up and rerun with a smaller time step. It's possible to do this safely under Windows on x86 if you read all the appropriate documents. It's not portable. That's why I'm aware of this mess.) So that's why resumable exceptions are a bad idea. John Nagle -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Mon, 06 Dec 2010 09:54:46 -0800, Dennis Lee Bieber wrote: > On Mon, 06 Dec 2010 00:14:11 -0800, Paul Rubin > declaimed the following in gmane.comp.python.general: > > >> exceptions that fixed the issue. Are there any languages out there >> with resumable exceptions? Escaping to a debugger doesn't really count >> as > > Visual BASIC 6 > > -=-=-=-=- > On Error GoTo line > REM Actions to sort out the error RESUME > Enables the error-handling routine that starts at line > specified in the required line argument. The line argument is any line > label or line number. If a run-time error occurs, control branches to > line, making the error handler active. The specified line must be in the > same procedure as the On Error statement; otherwise, a compile-time > error occurs. > Any BASIC that implements ON ERROR (i.e. just about all of them) will do this, not just VB. -- martin@ | Martin Gregorie gregorie. | Essex, UK org | -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 10:09 AM, Paul Rubin wrote: MRAB writes: When writing the C code for the new regex module I thought that it would've been easier if I could've used exceptions to propagate errors and unwind the stack, instead of having to return an error code which had to be checked by the caller, and then have the caller explicitly return an error code to /its/ caller. That's called longjmp. Automatic garbage collection would also have been nice. alloca might help. If you want proper exception unwinding, use C++, which has it. "longjmp" is a hack from the PDP-11 era. John Nagle -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Paul Rubin wrote: > m...@distorted.org.uk (Mark Wooding) writes: >> The most obvious improvement is resumable exceptions. > > You know, I've heard the story from language designers several times > over, that they tried putting resumable exceptions into their languages > and it turned out to be a big mess, so they went to termination > exceptions that fixed the issue. Are there any languages out there with > resumable exceptions? Escaping to a debugger doesn't really count as > that. I guess one way to do it would be call a coroutine to handle the > exception, and either continue or unwind after the continue returns, but > doing it in a single-threaded system just seems full of hazards. Apparently, at the end of his research, Alan Turing was trying out the idea of 'oracles', where a computable process would have access to an uncomputable process to get particular results. I would imagine that the idea here was to clarify what this would do to the computable process. If he had lived, I doubt that Turing would have built an oracle, but the idea does live on in interactive debuggers. It would seem if some situation has arisen that can be fixed by code, then you can just run that code there and then. Then 'resumable exceptions' just become a kind of subroutine call, perhaps like the triggers in SQL. Mel. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/05/10 15:52, Tim Harig wrote: > On 2010-12-05, Tim Harig wrote: >> Another, questionable but useful use, is to ignore the complex accounting >> of your position inside of a complex data structure. You can continue >> moving through the structure until an exception is raised indicating >> that you have reached a boundary of the structure. > > Here is another example in this vein. I had another example where using Exception as a control structure proves to be the most elegant solution. The problem was a logic puzzle solver (e.g. for Sudoku, Einstein's Logic problem, etc). The algorithm used is recursive backtracking solver (yes, I know there are more efficient constraint-based solver, but that's besides the point). The function modifies the `puzzle` list in-place such that after the call `puzzle` list will contain the solution to the puzzle (if any exists). The solving "in-place" is important since this solver thread runs in a "solver thread" and there is another "drawing thread" that draws the currently tested board asynchronously. This means we do not make a copy of the game board. No locking is done, since it is fine for the drawing thread to draw malformed board, and we do not want to compromise the solver's thread's speed. The two versions of using return value and exception: def solve_return(puzzle, index): """ return True when puzzle is solved, return False when backtracking or when no solution exists """ # recursion base case if all cells are filled and puzzle does not violate game rules: return True # solution found if puzzle violates game rules: return False # backtrack if puzzle[index] is unfilled: for i in possible_candidates(puzzle, index): puzzle[index] = i if solve(puzzle, index+1): # solution already found, unwinding the stack return True # all candidates failed, backtrack puzzle[r][c] = unfilled return False else: # the current cell is part of the base clue return solve(puzzle, index+1) # skip it def main_return(): puzzle = [...] if solve_return(puzzle, 0): print('solution found') else: print('no solution found') def solve_raise(puzzle, index): """ no return value throws SolutionFound when solution is found """ # recursion base case if all cells are filled and puzzle does not violate game rules: raise SolutionFound if puzzle[index] is unfilled: for i in possible_candidates(puzzle, index): puzzle[index] = i if puzzle does not violate game rules: solve(puzzle, index+1) # all candidates failed, backtrack puzzle[r][c] = unfilled else: # the current cell is part of the base clue solve(puzzle, index+1) # skip it def main_raise(): puzzle = [...] try: solve_raise(puzzle, 0) except SolutionFound: print('solution found') else: print('no solution found') Personally, I've found the logic in the exception version clearer than the return version. Also, the exception version is easier to extend, if I wanted to add a smarter algorithm that can deterministically infer certain cell's value (this creates indirect recursion, solve() may call either infer() or solve() which may call either infer() or solve()), it can work beside the existing mechanism without explicitly handling the return flag when a solution is found. If we suppose that end-of-line (e.g. the semicolon, in C-like language) is a single-step forward control structure, the if-statement is a n-step forward control structure, and looping is a n-step backward control structure. Now, if we suppose function call as a single-step downward control structure, and function return as a single-step upward control structure, then exception is a n-step upward control structure. It throws control upwards of the function call stack, while doing cleanup along its way up. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/6/2010 9:14 AM, Paul Rubin wrote: > m...@distorted.org.uk (Mark Wooding) writes: >> The most obvious improvement is resumable exceptions. > > You know, I've heard the story from language designers several times > over, that they tried putting resumable exceptions into their languages > and it turned out to be a big mess, so they went to termination > exceptions that fixed the issue. Are there any languages out there with > resumable exceptions? Escaping to a debugger doesn't really count as > that. I guess one way to do it would be call a coroutine to handle the > exception, and either continue or unwind after the continue returns, but > doing it in a single-threaded system just seems full of hazards. I seem to remember PL/1 has resumable exceptions, but I don't ever remember finding a real use for them. And it's so long since I used PL/1 I may be mistaken. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
m...@distorted.org.uk (Mark Wooding) writes: > The most obvious improvement is resumable exceptions. You know, I've heard the story from language designers several times over, that they tried putting resumable exceptions into their languages and it turned out to be a big mess, so they went to termination exceptions that fixed the issue. Are there any languages out there with resumable exceptions? Escaping to a debugger doesn't really count as that. I guess one way to do it would be call a coroutine to handle the exception, and either continue or unwind after the continue returns, but doing it in a single-threaded system just seems full of hazards. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 05/12/2010 21:01, Martin v. Loewis wrote: result = myfunction (vars) if not result: # error condition Now above I first realized that the function can also return an empty list under some conditions and so changed it to If your function returns a list when successful, it should not return False in the error case. Instead, it should return None (indicating that there is no list). Then the condition changes to result = myfunction() if result is None: # error condition Using None for "no result available" is very common in Python. Using False for the same purpose (i.e. returning either a list or False) is not. If you return False from a function, the only other possible result should be True. As an example, the re module uses both two approaches. If you ask it to compile a regex: rgx = re.compile(regex) it either returns a PatternObject (if the regex is valid) or raises an exception (if the regex isn't valid). If you ask it to search a string: rgx.search(string) it returns either a MatchObject (if the match is successful) or None (if the match isn't successful). -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
> result = myfunction (vars) > > if not result: > # error condition > > Now above I first realized that the function can also return an empty > list under some conditions and so changed it to If your function returns a list when successful, it should not return False in the error case. Instead, it should return None (indicating that there is no list). Then the condition changes to result = myfunction() if result is None: # error condition Using None for "no result available" is very common in Python. Using False for the same purpose (i.e. returning either a list or False) is not. If you return False from a function, the only other possible result should be True. Regards, Martin -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/04/2010 11:42 PM, Steven D'Aprano wrote: On Sun, 05 Dec 2010 04:13:02 +, Tim Harig wrote: str.find is more troublesome, because the sentinel -1 doesn't propagate and is a common source of errors: result = string[string.find(delim):] will return a plausible-looking but incorrect result if delim is missing from string. But the convenience and familiarity of str.find means it will probably be around forever. Fortunately, string objects offer both .find() and .index() so you can choose whether you want sentinels or exceptions according to your use-case. -tkc -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-05, Tim Harig wrote: > On 2010-12-05, Paul Rubin wrote: >> Tim Harig writes: >>> The fact that I bothered to create classes for the dice and roles, rather >>> then simply iterating over a list of numbers, should tell you that I >>> produced was of a far more flexible nature; including the support for >>> roles with dice having different numbers of sides. >> >> from itertools import product >> def n_sided_die(n): return xrange(1, n+1) >> >> # make one 3-sided die, one 4-sided die, and one 5-sided die >> dice = (n_sided_die(3), n_sided_die(4), n_sided_die(5)) >> for roll in product(*dice): >> print roll > > Notice that you had to change the structure of your program to accomodate > the new possiblity; and, if I throw further requirements at you, you > will have to change them again. I didn't want that. What the dice > returned may or may not have returned an easy to compute sequence. > In fact, for all of the rest of the logic cared, the dice could have > computed their value from a previous role of another dice. All of the > logic of about what the dice may have returned when asked for their > value and how they derived, was encapsilated in the dice themselves. > It did not need to be known anywhere else in the program logic. > > The DSL effectively provided a way do define how the dice decided how > to increment themselves, how to choose the value that they returned for > their face, and how to know when they could no longer be incremented. > The DSL parser generated the dice set from the description given. > Creating new dice objects was much easier then attempting to change the > logic of how they were rolled. > >>> I merely posted a simplied description of the dice-role objects >>> because I thought that it demonstrated how exceptions can provide >>> eligance of control for situations that don't involve what would >>> traditionally be defined as an error. >> >> Exceptions (though sometimes necessary) are messy and I'm having a hard >> time trying to envision that code being cleaner with them than without >> them. If you post the actual code maybe that will help me understand. > > Let me get this straight, the same person that was trying to tell me > setjmp/longjmp weren't messy thinks exceptions are messy? I have used > both. I much prefer the exceptions. I not have to code here to post. > > The cleanliness of using the exception and calling the dice increments > recursively, was that there was no need to figure out which dice needed > to be incremented whenever the first die needed to be reset. When a dice > needed to be reset, it would raise an exception. This exception would > rise through the recursion stack, and thus through the dice, resetting > each along the way until it found the one which needed to be incremented > or raised past the top call indicating that all of the combinations has > been exhausted. There, once the reset condition for the previous dice > had been effectively handled, it would be supprested. > > Had this been done using in band data: > > 1. The roll object would have needed logic to determine when > a reset condition needed to take place, effectively > leaking some of the logic from the dice object to the > role object. > > 2. The roll object would have needed logic to determine how to > follow the dice which needed to be reset until it found > which one needed incrementing. Once again, this logic > was better left to the dice walking the resets was > automatically handled by the progression of the exception. > > Even if it wasn't an error, the resets were effectively a exceptional > condition from the normal flow of the role object (the primary flow simply > being to increment the first die). By using exceptions, I effectively > isolated each into its own separate independent flow; and, because they > where called separatly, neither needed to have control conditions to detect > which was needed. They simply allowed the dice object to decide. Okay, it occures to me that you don't really need to see much to know what was going on, here is the basic idea of how the role function of the object would have looked like: def role(self, dice): try: self.role(dice.previous()) except diceReset: dice.increment() except endOfDice: raise diceReset -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-05, Paul Rubin wrote: > Tim Harig writes: >> The fact that I bothered to create classes for the dice and roles, rather >> then simply iterating over a list of numbers, should tell you that I >> produced was of a far more flexible nature; including the support for >> roles with dice having different numbers of sides. > > from itertools import product > def n_sided_die(n): return xrange(1, n+1) > > # make one 3-sided die, one 4-sided die, and one 5-sided die > dice = (n_sided_die(3), n_sided_die(4), n_sided_die(5)) > for roll in product(*dice): > print roll Notice that you had to change the structure of your program to accomodate the new possiblity; and, if I throw further requirements at you, you will have to change them again. I didn't want that. What the dice returned may or may not have returned an easy to compute sequence. In fact, for all of the rest of the logic cared, the dice could have computed their value from a previous role of another dice. All of the logic of about what the dice may have returned when asked for their value and how they derived, was encapsilated in the dice themselves. It did not need to be known anywhere else in the program logic. The DSL effectively provided a way do define how the dice decided how to increment themselves, how to choose the value that they returned for their face, and how to know when they could no longer be incremented. The DSL parser generated the dice set from the description given. Creating new dice objects was much easier then attempting to change the logic of how they were rolled. >> I merely posted a simplied description of the dice-role objects >> because I thought that it demonstrated how exceptions can provide >> eligance of control for situations that don't involve what would >> traditionally be defined as an error. > > Exceptions (though sometimes necessary) are messy and I'm having a hard > time trying to envision that code being cleaner with them than without > them. If you post the actual code maybe that will help me understand. Let me get this straight, the same person that was trying to tell me setjmp/longjmp weren't messy thinks exceptions are messy? I have used both. I much prefer the exceptions. I not have to code here to post. The cleanliness of using the exception and calling the dice increments recursively, was that there was no need to figure out which dice needed to be incremented whenever the first die needed to be reset. When a dice needed to be reset, it would raise an exception. This exception would rise through the recursion stack, and thus through the dice, resetting each along the way until it found the one which needed to be incremented or raised past the top call indicating that all of the combinations has been exhausted. There, once the reset condition for the previous dice had been effectively handled, it would be supprested. Had this been done using in band data: 1. The roll object would have needed logic to determine when a reset condition needed to take place, effectively leaking some of the logic from the dice object to the role object. 2. The roll object would have needed logic to determine how to follow the dice which needed to be reset until it found which one needed incrementing. Once again, this logic was better left to the dice walking the resets was automatically handled by the progression of the exception. Even if it wasn't an error, the resets were effectively a exceptional condition from the normal flow of the role object (the primary flow simply being to increment the first die). By using exceptions, I effectively isolated each into its own separate independent flow; and, because they where called separatly, neither needed to have control conditions to detect which was needed. They simply allowed the dice object to decide. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Tim Harig writes: > The fact that I bothered to create classes for the dice and roles, rather > then simply iterating over a list of numbers, should tell you that I > produced was of a far more flexible nature; including the support for > roles with dice having different numbers of sides. from itertools import product def n_sided_die(n): return xrange(1, n+1) # make one 3-sided die, one 4-sided die, and one 5-sided die dice = (n_sided_die(3), n_sided_die(4), n_sided_die(5)) for roll in product(*dice): print roll > I merely posted a simplied description of the dice-role objects > because I thought that it demonstrated how exceptions can provide > eligance of control for situations that don't involve what would > traditionally be defined as an error. Exceptions (though sometimes necessary) are messy and I'm having a hard time trying to envision that code being cleaner with them than without them. If you post the actual code maybe that will help me understand. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-05, Paul Rubin wrote: > Tim Harig writes: >> A friend was trying to derive a mathematical formula for determining >> the possibly distribution of results from rolling arbitrariy numbers >> of m n-sided dice > > http://en.wikipedia.org/wiki/Multinomial_distribution I sure he rediscovered much of that. Working that out for himeself was probably far more educational then simply reading an article on the solution. >> To generate a listing of all (non-uniq) possible roles, I would call >> the first dices increment method read and read the dice faces into a >> log until the first dice threw an exception that it could not be >> further incremented. Then I would call reset() on the first dice and >> increment the second and so on much like the odometer of a car. > > from itertools import product > m, n = 5, 2 > for roll in product(*(xrange(1,m+1) for i in xrange(n))): >print roll The fact that I bothered to create classes for the dice and roles, rather then simply iterating over a list of numbers, should tell you that I produced was of a far more flexible nature; including the support for roles with dice having different numbers of sides. I basically created a DSL that he could use to generate and automatically calculate the properties of series of roles defined by one or more varying property. I merely posted a simplied description of the dice-role objects because I thought that it demonstrated how exceptions can provide eligance of control for situations that don't involve what would traditionally be defined as an error. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Sun, 05 Dec 2010 04:13:02 +, Tim Harig wrote: > Anything it is an obvious > error *should* throw an exception. Well, maybe... there are good use-cases for returning a sentinel. E.g. str.find, or the use of quiet NANs in IEEE floating point and decimal maths. NANs and INFs in floating point maths are a good example of the right way to do it. If you forget to check for a NAN, it will propagate through your calculation. INF will, under some circumstances where it is mathematically valid to do so, will disappear leaving a normal result. This means you only need to check your result at the very end of the calculation, not after every step. str.find is more troublesome, because the sentinel -1 doesn't propagate and is a common source of errors: result = string[string.find(delim):] will return a plausible-looking but incorrect result if delim is missing from string. But the convenience and familiarity of str.find means it will probably be around forever. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Tim Harig writes: > A friend was trying to derive a mathematical formula for determining > the possibly distribution of results from rolling arbitrariy numbers > of m n-sided dice http://en.wikipedia.org/wiki/Multinomial_distribution > To generate a listing of all (non-uniq) possible roles, I would call > the first dices increment method read and read the dice faces into a > log until the first dice threw an exception that it could not be > further incremented. Then I would call reset() on the first dice and > increment the second and so on much like the odometer of a car. from itertools import product m, n = 5, 2 for roll in product(*(xrange(1,m+1) for i in xrange(n))): print roll -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-05, Tim Harig wrote: > Another, questionable but useful use, is to ignore the complex accounting > of your position inside of a complex data structure. You can continue > moving through the structure until an exception is raised indicating > that you have reached a boundary of the structure. Here is another example in this vein. A friend was trying to derive a mathematical formula for determining the possibly distribution of results from rolling arbitrariy numbers of m n-sided dice and needed several sets of data in different directions from which to draw conclusions. I created objects for dice and roles which contained and manipulated multiple dice. To generate a listing of all (non-uniq) possible roles, I would call the first dices increment method read and read the dice faces into a log until the first dice threw an exception that it could not be further incremented. Then I would call reset() on the first dice and increment the second and so on much like the odometer of a car. By using exceptions rather then checking the return value of increment, the state information of the dice was completely isolated to the dice and did not polute into the role structure; the logic for incrementing the dice, logging the role state, and rolling over the dice where all completely seperated and independent of any state; and therefore reseting multiple previous dice as the higher values on the odometer were incremented functioned automatically as each dice threw its own exception recursively rather then requiring logic to handle these multiple rollovers. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-05, Harishankar wrote: >> Or consider this code: >> >> if y != 0: >> result = x/y >> else: >> handle_division_by_zero() >> >> >> This is also unsafe unless you know the type of y. Suppose y is an >> interval quantity that straddles zero, then division by y may fail even >> though y != 0. > > Of course in each of these cases the in-built exceptions are used to > verify the result of certain system level or lower level operations. My > object was not to deprecate the system-level or other low level > exceptions thrown by Python, but to consider whether such a mechanism > would be a preferable method of handling your own programs error- > conditions. Whether you happen to like the exception mechanism and syntax or not, it is the idiomatic way of handling errors in Python. Using two different conventions in your code will lead to confusion. I come from a long C background as well. I have come to appreciate the power the Python's exception handling provides. It does everything that you need to do with passing values in C and more. > The issue to be considered by every programmer is to define what can be > defined as the exceptional condition and what is a condition that merits > merely different treatment without causing disruption of the normal flow > of the program. That is an issue much harder to define. Anything it is an obvious error *should* throw an exception. Invalid input is an error. Unusable hardware states are errors. Any invalid request to an object, is an error. Essentially anything that deviates from a normal flow of a program, to handle an exceptional condition, is an error Where it becomes less obvious is when you start using exceptions as part normal control flow. An example is a try it and see methodology. You might for instance have a group of file objects which might or might not support a particular method attribute. You might have a preference for using the attribute; but, have a fallback plan if it does not. One way to handle this is to try to use the attribute and catch the exception raised if it is not present to execute your backup method. I have found this *essential* in some marsaling enviroments where you might not have access to the meta-data of the object that you are working with. Another, questionable but useful use, is to ignore the complex accounting of your position inside of a complex data structure. You can continue moving through the structure until an exception is raised indicating that you have reached a boundary of the structure. Whether you accept uses of exceptions like these is more of a personal quesion. Like many good tools, they can be useful in ways that they were never really designed to be and I would hate to proclude some of these really useful features. This can, of course, be easily abused. I was once writing code, involving complex object marshaling like I described above, with a partner who wasn't totally familiar with Python. We came to a situation where it was impossible to know ahead of time what kind of object (one of two possiblities) we would receive from another marshalled object and had no meta-data to be able to figure out before attempting to access the object. I used a try/except clause to resolve the problem. The next day, I found several poorly conceived try/except blocks in the codebase that my partner had used for control structures using dictionaries because he didn't know of dict.has_key(). I was not so pleased. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Sun, 05 Dec 2010 01:59:27 +, Steven D'Aprano wrote: > Of course, this is mainly of theoretical concern. In practice, "Look > Before You Leap" (test first, then process) is often fine. But there are > traps to look out for. For example, unless you are running a single- > process machine, the following code is subject to race conditions and is > not safe: > > if os.exists(pathname): > fp = open(pathname) > else: > handle_missing_file() > > Just because the file is there when os.exists() looks for it, doesn't > mean it still exists a microsecond later when you try opening it. I understand this line of thinking. And it makes sense to see why it would matter to leave the exception handling mechanism deal with such issues. > > Or consider this code: > > if y != 0: > result = x/y > else: > handle_division_by_zero() > > > This is also unsafe unless you know the type of y. Suppose y is an > interval quantity that straddles zero, then division by y may fail even > though y != 0. Of course in each of these cases the in-built exceptions are used to verify the result of certain system level or lower level operations. My object was not to deprecate the system-level or other low level exceptions thrown by Python, but to consider whether such a mechanism would be a preferable method of handling your own programs error- conditions. The issue to be considered by every programmer is to define what can be defined as the exceptional condition and what is a condition that merits merely different treatment without causing disruption of the normal flow of the program. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Sat, 04 Dec 2010 17:07:45 +, Harishankar wrote: > I find a bit cumbersome > that exceptions are advocated for certain conditions which can be sanely > worked around in the application's logic and even avoided, rather than > waiting for them to get caught and providing an unsatisfactory result. That's surprisingly rare in Python. In fact, I'd go so far as to say that in Python there is *nothing* that you can test for and then have a *guarantee* that it will succeed. Of course, this is mainly of theoretical concern. In practice, "Look Before You Leap" (test first, then process) is often fine. But there are traps to look out for. For example, unless you are running a single- process machine, the following code is subject to race conditions and is not safe: if os.exists(pathname): fp = open(pathname) else: handle_missing_file() Just because the file is there when os.exists() looks for it, doesn't mean it still exists a microsecond later when you try opening it. Or consider this code: if y != 0: result = x/y else: handle_division_by_zero() This is also unsafe unless you know the type of y. Suppose y is an interval quantity that straddles zero, then division by y may fail even though y != 0. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/4/2010 12:07 PM, Harishankar wrote: Of course not. But going by the replies here, it appears that Python has made exceptions as the "norm" for error handling which is ironical considering the meaning of the word "exception". In communications parlance, 'exception' = out-of-band signal or return value, while 'return'ed value = in-band signal. A fake in-band return value, like returning None (ok) or False (worse) to *signal* 'I cannot return a list' is still an exception signal, even if 'in-band'. The advantage of out-of-band signals is that they cannot be mistaken for valid in-band signals (return values). If a caller neglects to catch an exception, the process stops, as it should. If a caller neglects to check return values, the process goes on (at least for a while) under the pretense that error codes (in-band exception signals) are valid return values. Neglecting to check return values for error codes is a common bug in C code. At worst, the process eventually return a bad value or performs a bad action. At best, it crashes sometime later, making the bug hard to find. Or a function is called without even storing, let alone checking the return value. This is common for i/o functions. A program may 'finish' without any indication that it failed. If one does the same with Python functions (equally common), any exceptions *will* be passed up until either caught or displayed on the screen with an informative traceback (assuming that the screen is the not source of the error). -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Sat, 4 Dec 2010 17:07:45 + (UTC) Harishankar wrote: > Of course not. But going by the replies here, it appears that Python has > made exceptions as the "norm" for error handling which is ironical > considering the meaning of the word "exception". I find a bit cumbersome > that exceptions are advocated for certain conditions which can be sanely > worked around in the application's logic and even avoided, rather than > waiting for them to get caught and providing an unsatisfactory result. It just seems to me that you have a semantic issue rather than a technical one. If the word "exception" was replaced by "check" or something else would that make the process easier to swallow? try: somefunc() check ValueError: handle_error() Whatever it's called it's just flow control. > > Quite often it's impossible for the function to know what needs to be > > done when a specific conditions arises, in which case (presumably) you > > have to return some error code and test for that ... > > Not necessarily. I wasn't talking about low-level or built-in exceptions. > I was talking about using exceptions in my programming where often the > function is reasonably confident of the kind of errors it is likely to > incur. I did not start this as a criticism of Python's exceptions as > such. I just expressed my personal aversion to using them in my own code. > > However, in my next project I have started using exceptions and will keep > an open mind on how it turns out. So far it doesn't seem too bad. Open minds are good. -- D'Arcy J.M. Cain | Democracy is three wolves http://www.druid.net/darcy/| and a sheep voting on +1 416 425 1212 (DoD#0082)(eNTP) | what's for dinner. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
> You appear to be suffering from the delusion that all exceptions must be > caught and handled. This is far from being the case. But still, better > to have your top-level code "littered with exception handlers" than to > have your functions "littered with if statements". Of course not. But going by the replies here, it appears that Python has made exceptions as the "norm" for error handling which is ironical considering the meaning of the word "exception". I find a bit cumbersome that exceptions are advocated for certain conditions which can be sanely worked around in the application's logic and even avoided, rather than waiting for them to get caught and providing an unsatisfactory result. > > Quite often it's impossible for the function to know what needs to be > done when a specific conditions arises, in which case (presumably) you > have to return some error code and test for that ... Not necessarily. I wasn't talking about low-level or built-in exceptions. I was talking about using exceptions in my programming where often the function is reasonably confident of the kind of errors it is likely to incur. I did not start this as a criticism of Python's exceptions as such. I just expressed my personal aversion to using them in my own code. However, in my next project I have started using exceptions and will keep an open mind on how it turns out. So far it doesn't seem too bad. > > regards > Steve -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 11:42 PM, Harishankar wrote: > One of the reasons why I feared to do this is because I need to know each > and every exception that might be thrown by the function and litter my > top-level code with too many exception handlers. > You appear to be suffering from the delusion that all exceptions must be caught and handled. This is far from being the case. But still, better to have your top-level code "littered with exception handlers" than to have your functions "littered with if statements". Quite often it's impossible for the function to know what needs to be done when a specific conditions arises, in which case (presumably) you have to return some error code and test for that ... regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-03, Harishankar wrote: > On Fri, 03 Dec 2010 14:31:43 +, Mark Wooding wrote: >> In general, recovering from an exceptional condition requires three >> activities: >> >> * doing something about the condition so that the program can continue >> running; >> >> * identifying some way of rejoining the program's main (unexceptional) >> flow of control; and >> >> * actually performing that transfer, ensuring that any necessary >> invariants are restored. > > my fault. Seems that exception handling requires a lot of forethought > since the control of program execution breaks at the point of exception > with no obvious way to rejoin it seamlessly whereas with an error, a > simple if condition could handle the error state and resume execution > from that point forward. This is the main reason why I think I used > simple error codes to handle certain recoverable conditions and avoided > exceptions. If you are returning an error code to the above function, then there is nothing that you cannot do with with the exception. Basically, you resolve the issue in your except block just as you would in the block of your if statement after returning the error code. If you try and fail to handle the exception or just needed to do some cleanup before allowing the exception to continue, then you just re-raise the exception. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-04, alex23 wrote: > On Dec 3, 2:12 am, Tim Harig wrote: >> Actually, I thought that debate was resolved years ago. I cannot think of >> a single recently developed programming language that does not provide >> exception handling mechanisms because they have been proven more reliable. > > Google's Go lacks exceptions and I believe that was a deliberate > design choice. 1. The debate that I was referring to was between simple function checking vs. everything else. I didn't mean to automatically proclude any newer methodologies of which I might not even be aware. 2. I would consider the defer/panic/recovery mechanism functionally similar to exceptions in most ways. It allows the error handling code to be placed at a higher level and panics tranverse the stack until they are handled by a recovery. This is basically equivilent to how exceptions work using different names. The change is basically the defer function which solves the problem of any cleanup work that the function needs to do before the panic is raised. I like it, its nice. It formalizes the pattern of cleaning up within an exception block and re-raising the exception. I do have to wonder what patterns will emerge in the object given to panic(). Since it takes anything, and since Go doesn't have an object hierarchy, much less an exception hierarchy, the panic value raised may or may not contain the kind of detailed information that can be obtained about the error that we are able to get from the Exception objects in Python. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Dec 3, 2:12 am, Tim Harig wrote: > Actually, I thought that debate was resolved years ago. I cannot think of > a single recently developed programming language that does not provide > exception handling mechanisms because they have been proven more reliable. Google's Go lacks exceptions and I believe that was a deliberate design choice. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
In article , Harishankar wrote: >On Thu, 02 Dec 2010 17:33:47 -0800, Aahz wrote: >> >> Please demonstrate that using ``if`` blocks for True/False is impler and >> cleaner than using ``try`` blocks to handle exceptions. > >It is my personal preference and coding style for certain situations I >encounter in my own programs and not something that I could prove to >anybody else by theory. Note carefully that I said "demonstrate", not "prove". If using ``if`` is so clearly better in some situations, you should be able to provide an example. -- Aahz (a...@pythoncraft.com) <*> http://www.pythoncraft.com/ "Think of it as evolution in action." --Tony Rand -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/3/2010 6:31 AM Mark Wooding said... It's easy to show that a resumable exception system can do everything that a nonresumable system (like Python's) can do (simply put all of the recovery logic at the resume point); but the converse is not true. There are some other fringe benefits to resumable exceptions. I do a lot of work in a variant of Business Basic that has always offered resumable exceptions. The closest I get in python is using import pdb;pdb.set_trace(). I wonder what it would take to allow for any exceptions occurring outside a try/except context to dump the traceback, then invoke pdb.set_trace() before bailing to allow for both investigation and possible recovery and continuance? Emile -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 17:33:47 -0800, Aahz wrote: > Please demonstrate that using ``if`` blocks for True/False is impler and > cleaner than using ``try`` blocks to handle exceptions. It is my personal preference and coding style for certain situations I encounter in my own programs and not something that I could prove to anybody else by theory. But anyway, in certain circumstances, exceptions create a break in flow of the execution of a program that makes it non-obvious as to how to resume flow at the point of disruption especially when the exception handling mechanism is at a higher level. While an error flag can simply set an alarm and allow other code to continue and allow the calling higher-level code to handle the alarm/flag as it sees fit. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Fri, 03 Dec 2010 14:31:43 +, Mark Wooding wrote: > The most obvious improvement is resumable exceptions. This is probably what I had in mind but I just couldn't explain it the way you did below. > > In general, recovering from an exceptional condition requires three > activities: > > * doing something about the condition so that the program can continue > running; > > * identifying some way of rejoining the program's main (unexceptional) > flow of control; and > > * actually performing that transfer, ensuring that any necessary > invariants are restored. This really sums up my thoughts about exceptions better than I could have explained! I just felt instinctively that I had missed something, but it appears to be a break in logic of the code somewhere which I thought was my fault. Seems that exception handling requires a lot of forethought since the control of program execution breaks at the point of exception with no obvious way to rejoin it seamlessly whereas with an error, a simple if condition could handle the error state and resume execution from that point forward. This is the main reason why I think I used simple error codes to handle certain recoverable conditions and avoided exceptions. I quite enjoyed your post. Thank you for explaining a lot of issues which I probably could not have figured out on my own. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Steven D'Aprano writes: > On Thu, 02 Dec 2010 16:35:08 +, Mark Wooding wrote: > > There are better ways to handle errors than Python's exception system. > > I'm curious -- what ways would they be? The most obvious improvement is resumable exceptions. In general, recovering from an exceptional condition requires three activities: * doing something about the condition so that the program can continue running; * identifying some way of rejoining the program's main (unexceptional) flow of control; and * actually performing that transfer, ensuring that any necessary invariants are restored. Python's `try ... finally' helps with the last; but Python intertwines the first two, implementing both with `try ... except'. The most important consequence of this is that the logic which contains knowledge about how to fix the condition must be closer to the code that encountered the condition than the resume point is. It's therefore hard to factor out high-level policy about fixing conditions from the relatively tedious business of providing safe points at which to resume main execution. (Effectively, each section of your program which wants to avail itself of some high-level condition-fixing policy has to provide its own protocol for expressing and implementing them.) Phew. That was abstract. Can I come up with some examples? I've been writing a (sort of) compiler recently. When it encounters errors, it reports a message to the user containing the position it had reached in the source, updates a counter so that it can report a summary at the end of the run and produce a sensible exit status, and then attempts to carry on compiling as best it can. The last bit -- attempting to carry on as best it can -- needs local knowledge of what the compiler's doing and what actually went wrong. If the parser expected to find a delimiter, maybe it should pretend that it found one, for example. The other stuff, printing messages, updating counters, and so on, is all done with some condition handlers wrapped around the meat of the compiler. That's written only once. Everything that signals errors, including standard I/O functions like open-a-file, gets the same treatment. (The remaining missing ingredient is a fluid variable which tracks the current position in the source and is updated by the scanner; bits of the compiler's semantic analysis machinery will temporarily focus attention on other parts of the source using locations they saved during the parse. Implementing fluids in Python can be done with a context manager: if you don't care about concurrency then you can use simple variables; otherwise it's little fiddly and the syntax isn't very comfortable, but it's still possible.) A more familiar example, maybe, is the good old DOS `abort/retry/fail' query. Implementing such a thing in Python, as a general policy for handling I/O errors, isn't possible. Viewed narrowly, this is probably a good thing: the old DOS query was very annoying. But the difficulty of implementing this policy illustrates the missing functionality. And, of course, if DOS had a proper resumable exception system, programs could have overridden the annoying query. In general, the code which discovers an exceptional condition may have several options for how to resume. It might be possible to ignore the situation entirely and carry on regardless (`false alarm!'). It might be possible to try again (`transient failure'). Alas, the logic which is capable of implementing these options is usually too low-level and too close to the action to be able to decide among them sensibly. (Maybe a human user should be consulted -- but that can drag in user interface baggage into a low-level networking library or whatever.) Resumable exceptions provide a way out of this mess by separating the mechanics of resumption from policy of which resumption option to choose. It's easy to show that a resumable exception system can do everything that a nonresumable system (like Python's) can do (simply put all of the recovery logic at the resume point); but the converse is not true. There are some other fringe benefits to resumable exceptions. * It's usual to report a stack backtrace or similar if an exception occurs but nothing manages to resume execution. If unwinding the stack is intertwined with working out how to resume execution, then whenever you /try/ to run an applicable handler, you have to reify the stack context and stash it somewhere in case the handler doesn't complete the job. This makes raising exceptions more expensive than they need to be. * You can use the same mechanism for other kinds of communication with surrounding context. For example, Python occasionally emits `warnings', which have their own rather simple management system (using global state, so it's hard to say `don't issue MumbleWarnings while we frob the widgets' in a concurrent program). A resumable ex
Re: Comparison with False - something I don't understand
Harishankar wrote: > I think I understand the general trend of what you're saying. It > definitely requires a mindset change. I still feel that user-defined > exception classes might not be the way, but maybe I should allow the > built-in exceptions which are thrown by library functions to follow its > natural path upwards till it reaches the top level where it could be > handled. User-defined exception classes are no big deal, and I think they're helpful. At the minimum, they're just a few lines in a module, e.g.: class SumpError (StandardError): '''Errors raised by the SUMP client.''' class SumpIdError (SumpError): '''The wrong string was returned by an ID request.''' class SumpFlagsError (SumpError): '''Illegal combination of flags.''' class SumpStageError (SumpError): '''Illegal trigger stage setting.''' This is from a module to drive some special hardware through a serial connection. At this stage in development, I don't even have try/except statements for these. It's enough that some typo will not silently put the hardware into an illegal state, and instead will report Traceback (most recent call last): File "logic_sniffer.py", line 184, in OnDeviceCapture set_sump_options (grabber) File "logic_sniffer.py", line 21, in set_sump_options sump.set_flags (demux=True, filter=True, channel_groups=0x0, external=False, inverted=False) # only 1 channel group File "/home/mwilson/sandbox/sump-analyzer/sump.py", line 160, in set_flags raise SumpFlagsError sump.SumpFlagsError Because these are subclasses of StandardError, they'll be caught by any `except StandardError`, which may or may not turn out to be a mistake. Once development is done, try/except for these will be in some window methods as part of a wxPython GUI, several call levels above the code that would raise the exceptions, up where a human user would take steps to change the way things are being done, or submit a bug report (more likely), or something. > Maybe I should handle the error only at the highest level (UI level) > rather than returning False to flag errors. > > One of the reasons why I feared to do this is because I need to know each > and every exception that might be thrown by the function and litter my > top-level code with too many exception handlers. The advantage to the exceptions, is that they only need to be recognized and caught and handled at the UI level. They don't have to be recognized and passed back up the call chain from level to level till they get to the right place -- the way out-of-band error returns have to be. Mel. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-03, Paul Rubin wrote: > Steven D'Aprano writes: >>> There are better ways to handle errors than Python's exception system. >> I'm curious -- what ways would they be? >> I'm aware of three general exception handling techniques: ... >> What else is there? > > The Erlang approach is to chop the application into a lot of very > lightweight processes, and let any process that encounters an error > simply crash. A monitoring process notices the crashed process and > restarts it. There is a "supervision tree" of uber-monitor processes > that restart crashed monitor proceses. I haven't programmed in that > style myself and I'm not persuaded that it's better than what Python > does, but I think it's different from the stuff on your list, which is Erlang also offers an exception syntax almost identical to Python's for use within a single process. What makes Erlang's supervisor mode of error handling superior is that it works for more then just the current vm. If a process throws an exception, the supervisor catches and handles it. If a vm dies, a supervisor from another vm takes over. If an entire computer dies, a supervisor on another computer takes over. OTP provides some extremely advanced support for supervisory structures. > an answer to your "what else is there". I do know that they write some > complex, very high reliability systems (phone switches) in Erlang. Erlang isn't what I would call a very general purpose programming language like Python; but, if you want to build highly scalable and/or highly available systemes, there really isn't anything else that comes close to it. I am not really a huge fan of the purely functional nature of the language; but, light weight processes using the actor model is the way to go for concurrent processing. The BEAM virtual machine is also a powerful system with its ability to patch systems on the fly. It has start to become the target for other languages. I know of two that are in current developement. I wouldn't mind seeing a version of Python that could leverage the power of the BEAM vm. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Steven D'Aprano writes: >> There are better ways to handle errors than Python's exception system. > I'm curious -- what ways would they be? > I'm aware of three general exception handling techniques: ... > What else is there? The Erlang approach is to chop the application into a lot of very lightweight processes, and let any process that encounters an error simply crash. A monitoring process notices the crashed process and restarts it. There is a "supervision tree" of uber-monitor processes that restart crashed monitor proceses. I haven't programmed in that style myself and I'm not persuaded that it's better than what Python does, but I think it's different from the stuff on your list, which is an answer to your "what else is there". I do know that they write some complex, very high reliability systems (phone switches) in Erlang. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 16:35:08 +, Mark Wooding wrote: >> 3. Philosophically I think exception handling is the wrong approach to >> error management. > > There are better ways to handle errors than Python's exception system. I'm curious -- what ways would they be? I'm aware of three general exception handling techniques: 1. return a sentinel value or error code to indicate an exceptional case (e.g. str.find returns -1); 2. raise an exception (e.g. nearly everything else in Python); 3. set an error code somewhere (often a global variable) and hope the caller remembers to check it; plus some de facto techniques sadly in common use: 4. dump core; 5. do nothing and produce garbage output. What else is there? -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-03, Harishankar wrote: > On Thu, 02 Dec 2010 16:52:57 +, Tim Harig wrote: > >> If you are having that issue, then you are likely placing the try blocks >> at too low of a level in your code. In general you will find that most >> systems have a gateway function as an entry point to the system. If >> there is not one already, then create such a function in you code. The >> parse function in my code above would be an example of such a gateway >> function. Beneath that function, you don't need to know exactly where >> the error occured, you just need to know the nature of the error and >> have general error handling procedures for each kind of error that you >> expect might occur. > > I think I might very well by using try blocks rather defensively rather > than letting the code reach its logical conclusion in normal > circumstances. This is why I think I find it a bit clunky. That was the conclusion I was coming to. > I think I understand the general trend of what you're saying. It > definitely requires a mindset change. I still feel that user-defined > exception classes might not be the way, but maybe I should allow the > built-in exceptions which are thrown by library functions to follow its > natural path upwards till it reaches the top level where it could be > handled. Look at it this way, in C you were constrained to place your error handling code around ever function that might fail. Now you are free to place the error handling code wherever it makes sense to do so. As a general rule, if, in C, your function would handle the error by passing an error return value to the calling function, then the error handling code should be higher up. > Maybe I should handle the error only at the highest level (UI level) > rather than returning False to flag errors. I don't write many UIs; but, I normally consider the UI code to be yet another subsystem. In general, I find the best place to place error handling code in the high level business logic of your application (which might be what you actually meant by UI, to me the UI code is the code that actually draws the interface), in the high level logic of the systems, and in the bounderies between subsystems. The exceptions caught at each level depend on where the logic to handle the error is best applied. > One of the reasons why I feared to do this is because I need to know each > and every exception that might be thrown by the function and litter my > top-level code with too many exception handlers. Each exception has a place where it is better handled. Wherever you find boundaries between subsystems, think about what error conditions that subsystem might encounter. Subsystems dealing with are likely to encounter io related errors, network subsystems network errors, parsers validation errors etc. Logic exceptions that indicate errors in your code should be left alone entirely so that they may be easily found. Look at the exceptions pertaining to these subsystems. For each error reaching the boundery, think about whether you have enough information within the module to handle the error in a constructive manner or whether the error handling would benefit from information further up in the program. If you have all of the information that you need then handle it in the main logic of that subsystem. If not, pass it up to the error handlers on top of the boundry. When you get there, make the same decision. In general you only need to catch a handful of exceptions at each level. The easy excpetions will be handled at lower levels. The most difficult exceptions will rise towards the top of the program until only the terminal exceptions, that cannot be resolved are left with the inevitable result that you should notify the user and exit, will remain. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 16:52:57 +, Tim Harig wrote: > If you are having that issue, then you are likely placing the try blocks > at too low of a level in your code. In general you will find that most > systems have a gateway function as an entry point to the system. If > there is not one already, then create such a function in you code. The > parse function in my code above would be an example of such a gateway > function. Beneath that function, you don't need to know exactly where > the error occured, you just need to know the nature of the error and > have general error handling procedures for each kind of error that you > expect might occur. I think I might very well by using try blocks rather defensively rather than letting the code reach its logical conclusion in normal circumstances. This is why I think I find it a bit clunky. I think I understand the general trend of what you're saying. It definitely requires a mindset change. I still feel that user-defined exception classes might not be the way, but maybe I should allow the built-in exceptions which are thrown by library functions to follow its natural path upwards till it reaches the top level where it could be handled. Maybe I should handle the error only at the highest level (UI level) rather than returning False to flag errors. One of the reasons why I feared to do this is because I need to know each and every exception that might be thrown by the function and litter my top-level code with too many exception handlers. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Fri, 03 Dec 2010 08:06:35 +1100, Ben Finney wrote: > Raise exceptions for exceptional cases, and define the function > interface so that it's doing one clear job only. Often that involves > breaking a complicated function into several collaborating functions > with simpler interfaces. This is probably what I should try to do. Of course my function returns only a list in most circumstances. Only in error does it return False. I mis-represented the None type for the empty list in my previous post, my apologies. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
In article , Harishankar wrote: > >There are some reasons why I hate exceptions but that is a different >topic. However, in short I can say that personally: > >1. I hate try blocks which add complexity to the code when none is >needed. Try blocks make code much more unreadable in my view and I use it >only for the built-in exceptions when absolutely needed. > >2. I prefer the less irksome True or False to do error checking. >Exceptions seem too heavyweight for simple problems. Please demonstrate that using ``if`` blocks for True/False is impler and cleaner than using ``try`` blocks to handle exceptions. -- Aahz (a...@pythoncraft.com) <*> http://www.pythoncraft.com/ "Think of it as evolution in action." --Tony Rand -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 10:13 AM, Terry Reedy wrote: Aside from the other issues raised, I will just note that is more common to return None when there is no answer (for whatever reason) rather than False and explicitly compare 'is None' than 'is False'. The basic problem is that the original design of Python lacked a "bool" type. Classic language design error. It seems reasonable to people not familiar with programming language history to let True be equivalent to 1 and False be equivalent to 0, but it doesn't work out well. Retrofitting a "bool" type never quite works right. C/C++ went through this decades ago. The semantics of integers are clear, and the semantics of booleans are clear, but the semantics of mixed booleans and integers are not. You get questions like the one in this thread. Related questions include the semantics of x = True + True What's the value of "x"? "True"? 2? Is "+" between two "Bool" items addition, logical OR, or an error? The same problem applies to "*". The arguments on either side can be seen in PEP 285, but they gloss over the fact that the original design was botched. Similar design errors show up in other places in Python. Using "+" for concatenation seemed reasonable, but didn't scale out well, especially after NumPy's "array" type was introduced. [1,2,3] + [4,5,6] and array([1,2,3]) + array([4,5,6]) produce quite different results. Worse, what should array([1,2,3]) + [4,5,6] do? It doesn't raise an exception. I went to a talk by Alexander Stepanov at Stanford recently, where he talked about problems in the fundamentals of programming. This is one of the issues that came up. Defining addition in a way that is not associative and commutative leads to problems, and breaks generic algorithms. If the basic operators follow the expected rules, generic algorithms will work on them. That was botched in Python. John Nagle -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Harishankar writes: > On Thu, 02 Dec 2010 22:19:25 +1100, Ben Finney wrote: > > > More details of the problem you're trying to solve would help with > > giving specific advice. > > I'm writing functions with multiple points of failure exits. I use > return False as a way to flag the error condition rather than raising > exceptions. That's not much detail. Based only on that, I would say you should be raising an exception at each “point of failure”, preferably of a type defined for the purpose, instead of returning False. > But under certain circumstances, the function can also return empty > lists The function returns boolean, list, and None types? That's very much a case where the function is trying to do too many things with the return value. Raise exceptions for exceptional cases, and define the function interface so that it's doing one clear job only. Often that involves breaking a complicated function into several collaborating functions with simpler interfaces. -- \“Pinky, are you pondering what I'm pondering?” “Umm, I think | `\ so, Brain, but three men in a tub? Ooh, that's unsanitary!” | _o__) —_Pinky and The Brain_ | Ben Finney -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Paul Rubin wrote: > Tim Harig writes: >> I am not talking about what setjmp() has to do, I am talking about what >> *you* have to do after setjmp() returns. If you have allocated memory in >> intermediate functions and you don't have a reference to them outside of >> the functions that longjmp() bypasses from returning properly (and thus >> either not clearning data structures or returning a reference to those data >> structures as it normally would) then you have potential memory leaks, >> dangling pointers, etc. > > Sure, that's what the aux stack is for--you put any such references into > it, for the setjmp handler to find later. You do that BEFORE setjmp > returns, of course. If you miss something, you are in trouble. There is a concept of variable life that is measured by how many lines separate the use of variable from its first use to its last. By using setjmp/longjmp, you effectively extend the life of these variables, potentially through several files, to at least as long as the jump. If there are several function calls in depth, there may be quite a lot of space that you have to check to make sure that you have not missed anything. >> I am not saying that this cannot be done. What I am saying is that it >> is inherently error prone. > > I suppose so, but so is everything else in C. On the overall scale of > C-related hazards, this particular one isn't so bad if you code in a > consistent style and are disciplined about recording the cleanups. > > You could also use something like an obstack, which is a stack allocated > on the heap, so it persists after the control stack returns, but you can > release the whole thing in one operation. By working the error back up through the call stack, you can keep track of the variables and allocations in each function isolated to that function. The smaller each function is, the easier and less error prone it will be to theck it is to check. That makes it much easier to make sure that you have not missed anything. Essentially, you can validate that each function correctly handles is allocations rather then having to validate the setjmp/longjmp structure as a whole. To use Joe Armstrong's phrase, "it makes the impossible merely difficult." Back to the topic, by using Python with its exceptions and garbage collection, all of this is a moot point. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, MRAB wrote: > On 02/12/2010 19:15, Tim Harig wrote: >> On 2010-12-02, Paul Rubin wrote: >>> Tim Harig writes: > longjmp. Alternatively you can have an auxiliary stack of cleanup > records that the longjmp handler walks through. Of course if you do Only if you already have pointers to *all* of the data structures at the point where you put your setjmp(). >>> >>> The setjmp point only has to know where the aux stack is and its depth >>> when the longjmp happens. The cleanup records contain any necessary >>> pointers to data structures that need freeing. That is basically how >>> try/finally would do it too. This is pretty standard stuff. >> >> I am not talking about what setjmp() has to do, I am talking about what >> *you* have to do after setjmp() returns. If you have allocated memory in >> intermediate functions and you don't have a reference to them outside of >> the functions that longjmp() bypasses from returning properly (and thus >> either not clearning data structures or returning a reference to those data >> structures as it normally would) then you have potential memory leaks, >> dangling pointers, etc. >> >> I am not saying that this cannot be done. What I am saying is that it >> is inherently error prone. > > Automatic garbage collection is nice to have when using exceptions > precisely because it's automatic, so unwinding the stack is much safer. Indeed. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Tim Harig writes: > I am not talking about what setjmp() has to do, I am talking about what > *you* have to do after setjmp() returns. If you have allocated memory in > intermediate functions and you don't have a reference to them outside of > the functions that longjmp() bypasses from returning properly (and thus > either not clearning data structures or returning a reference to those data > structures as it normally would) then you have potential memory leaks, > dangling pointers, etc. Sure, that's what the aux stack is for--you put any such references into it, for the setjmp handler to find later. You do that BEFORE setjmp returns, of course. > I am not saying that this cannot be done. What I am saying is that it > is inherently error prone. I suppose so, but so is everything else in C. On the overall scale of C-related hazards, this particular one isn't so bad if you code in a consistent style and are disciplined about recording the cleanups. You could also use something like an obstack, which is a stack allocated on the heap, so it persists after the control stack returns, but you can release the whole thing in one operation. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 02/12/2010 19:15, Tim Harig wrote: On 2010-12-02, Paul Rubin wrote: Tim Harig writes: longjmp. Alternatively you can have an auxiliary stack of cleanup records that the longjmp handler walks through. Of course if you do Only if you already have pointers to *all* of the data structures at the point where you put your setjmp(). The setjmp point only has to know where the aux stack is and its depth when the longjmp happens. The cleanup records contain any necessary pointers to data structures that need freeing. That is basically how try/finally would do it too. This is pretty standard stuff. I am not talking about what setjmp() has to do, I am talking about what *you* have to do after setjmp() returns. If you have allocated memory in intermediate functions and you don't have a reference to them outside of the functions that longjmp() bypasses from returning properly (and thus either not clearning data structures or returning a reference to those data structures as it normally would) then you have potential memory leaks, dangling pointers, etc. I am not saying that this cannot be done. What I am saying is that it is inherently error prone. Automatic garbage collection is nice to have when using exceptions precisely because it's automatic, so unwinding the stack is much safer. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 1:31 PM, Terry Reedy wrote: > It turns out that try block are computationally lighter weight (faster) > for normal execution ;-) Though that alone would hardly be sufficient reason to use them. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Paul Rubin wrote: > Tim Harig writes: >>> longjmp. Alternatively you can have an auxiliary stack of cleanup >>> records that the longjmp handler walks through. Of course if you do >> >> Only if you already have pointers to *all* of the data structures at >> the point where you put your setjmp(). > > The setjmp point only has to know where the aux stack is and its depth > when the longjmp happens. The cleanup records contain any necessary > pointers to data structures that need freeing. That is basically how > try/finally would do it too. This is pretty standard stuff. I am not talking about what setjmp() has to do, I am talking about what *you* have to do after setjmp() returns. If you have allocated memory in intermediate functions and you don't have a reference to them outside of the functions that longjmp() bypasses from returning properly (and thus either not clearning data structures or returning a reference to those data structures as it normally would) then you have potential memory leaks, dangling pointers, etc. I am not saying that this cannot be done. What I am saying is that it is inherently error prone. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Tim Harig writes: >> longjmp. Alternatively you can have an auxiliary stack of cleanup >> records that the longjmp handler walks through. Of course if you do > > Only if you already have pointers to *all* of the data structures at > the point where you put your setjmp(). The setjmp point only has to know where the aux stack is and its depth when the longjmp happens. The cleanup records contain any necessary pointers to data structures that need freeing. That is basically how try/finally would do it too. This is pretty standard stuff. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Paul Rubin wrote: > Tim Harig writes: >>> That's called longjmp. >> >> The problem is that you might have partially allocated data structures >> that you need to free before you can go anywhere. > > Alloca can help with that since the stack stuff gets released by the > longjmp. Alternatively you can have an auxiliary stack of cleanup alloca() only helps if you actually *want* the data stored on the stack. There are many reasons one might prefer or need that the data in the heap. > longjmp. Alternatively you can have an auxiliary stack of cleanup > records that the longjmp handler walks through. Of course if you do Only if you already have pointers to *all* of the data structures at the point where you put your setjmp(). This approach is error prone. > records that the longjmp handler walks through. Of course if you do > that, you're halfway towards reinventing exceptions. Exactly. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 02/12/2010 18:09, Paul Rubin wrote: MRAB writes: When writing the C code for the new regex module I thought that it would've been easier if I could've used exceptions to propagate errors and unwind the stack, instead of having to return an error code which had to be checked by the caller, and then have the caller explicitly return an error code to /its/ caller. That's called longjmp. The problem with that is that the caller might have to do some tidying up, such as deallocation. Exceptions give the caller the chance of catching it (ideally in a 'finally' block), tidying up, and then propagating. Automatic garbage collection would also have been nice. alloca might help. I didn't know about that. It looks like that's allocated on the stack, and the allocation I'm talking must be on the heap, so it's not suitable anyway. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Paul Rubin wrote: > MRAB writes: >> When writing the C code for the new regex module I thought that it >> would've been easier if I could've used exceptions to propagate errors >> and unwind the stack, instead of having to return an error code which >> had to be checked by the caller, and then have the caller explicitly >> return an error code to /its/ caller. > > That's called longjmp. In theory. In practice, using longjump for that without blowing your foot off isn't easy. >> Automatic garbage collection would also have been nice. > > alloca might help. And that's almost as easy to screw up. :) -- Grant Edwards grant.b.edwardsYow! I want EARS! I want at two ROUND BLACK EARS gmail.comto make me feel warm 'n secure!! -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Tim Harig writes: >> That's called longjmp. > > The problem is that you might have partially allocated data structures > that you need to free before you can go anywhere. Alloca can help with that since the stack stuff gets released by the longjmp. Alternatively you can have an auxiliary stack of cleanup records that the longjmp handler walks through. Of course if you do that, you're halfway towards reinventing exceptions. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 9:56 AM, Harishankar wrote: There are some reasons why I hate exceptions but that is a different topic. However, in short I can say that personally: 1. I hate try blocks which add complexity to the code when none is needed. Try blocks make code much more unreadable in my view and I use it only for the built-in exceptions when absolutely needed. 2. I prefer the less irksome True or False to do error checking. Exceptions seem too heavyweight for simple problems. It turns out that try block are computationally lighter weight (faster) for normal execution ;-) 3. Philosophically I think exception handling is the wrong approach to error management. I have never grown up programming with exceptions in C and I couldn't pick up the habit with python either. Did I mention that I detest try blocks? try blocks seem ugly and destroy code clarity at least in my view. And enclosing single statements under separate try blocks seem to add a lot of clutter. Having also come to Python directly from C, I can sympathize. It took me a while to adjust. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Paul Rubin wrote: > MRAB writes: >> When writing the C code for the new regex module I thought that it >> would've been easier if I could've used exceptions to propagate errors >> and unwind the stack, instead of having to return an error code which >> had to be checked by the caller, and then have the caller explicitly >> return an error code to /its/ caller. > > That's called longjmp. The problem is that you might have partially allocated data structures that you need to free before you can go anywhere. Jumping up several levels, without letting the intermediate levels do their cleanup could easily lead to a memory leak or worse. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Aside from the other issues raised, I will just note that is more common to return None when there is no answer (for whatever reason) rather than False and explicitly compare 'is None' than 'is False'. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
MRAB writes: > When writing the C code for the new regex module I thought that it > would've been easier if I could've used exceptions to propagate errors > and unwind the stack, instead of having to return an error code which > had to be checked by the caller, and then have the caller explicitly > return an error code to /its/ caller. That's called longjmp. > Automatic garbage collection would also have been nice. alloca might help. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 02/12/2010 16:12, Tim Harig wrote: On 2010-12-02, Harishankar wrote: I understand that the error vs exception debate is quite a big one in the programming community as a whole and I don't consider myself very Actually, I thought that debate was resolved years ago. I cannot think of a single recently developed programming language that does not provide exception handling mechanisms because they have been proven more reliable. Python. I do understand both sides of the issue. Exceptions seem to be generally more reliable but I feel they add a lot of complexity particular when a lot of code is placed in a try block. Lines of code is one measure of complexity. Each line of code has a small chance of containing a bug. The more lines of code that you have, then the more likely that one of them contains a bug. Exceptions, by placing error handling code in fewer places, requires much fewer lines of code then requiring error handling code after each call that might produce an error condition. The operations of propogating an error up to the higher level logic of the program is another measure. In languages without exception handling, careful planning is needed to pass error conditions up through the call stack until they reach a high enough level in the logic that decisions can be made about how to handle them. Even further planning must be taken so that when the error condition reaches level where it needs to be handled, that enough information about the error is present to know exactly what went wrong so that it can figure out what to do about it. This usually involves using globals like errorno to pass out of band information about the error. Sometimes you even need to know about how the error affect intermediate levels, did the intermediate code attempt to handle the condtion and fail? The Openssl error handling system, that creates an error logging chain is an example of just how complex this can become. You gain all of this functionality automatically through exception mechanisms; without all of the complexity. When writing the C code for the new regex module I thought that it would've been easier if I could've used exceptions to propagate errors and unwind the stack, instead of having to return an error code which had to be checked by the caller, and then have the caller explicitly return an error code to /its/ caller. Automatic garbage collection would also have been nice. You don't realise how nice it is to have such things until you have to go without them. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Harishankar wrote: As I said before, the way exceptions are caught seem to me to be the most confusing bit. Non-atomic operations always worry me. What if my function which is wrapped inside a try block has two different statements that raised the same exception but for different reasons? With error handling I could probably handle it right below the statement which was called and thus reduce the problem??? Exception actually are the solution as you can give an unlimitted quantity of information: def myfunction(self): error = myfuncException('a meaninful message') # error 1 error.blame = whateverobjectresponsibleoftheerror # error 2 error.blame = anotherobject_anothercause raise error try: myfunction() except myfuncException, exception: cause = exception.blame # you can inspect the 'cause' for specific handling In a more general and simple manner, you can tune the error feedback of exceptions by changing the message of the exception. Using different exception classes is also an obvious way to do it. But my point was that you can also set attributes to the exception you're raising with reference to almost anything at the time the exception occurs. And that is a very cool way to give precise feedback to exception handlers. JM -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Harishankar wrote: >> Actually, finer grained error handling commonly covers up bugs. If you >> want to find bugs, you want to make the program prone to crashing if a >> bug is present. It is all too easy to accidently mistake the return >> value of a function as error condition and handle it rather the letting >> the program crash. By separating the results from the transmission of >> error conditions (in effect taking error conditions out of band) then >> you make it much harder to make such a mistake because you have to >> explicity indicate which error conditions your code is capable of >> generating. > > Doesn't the same finer grained exception mechanism make it prone to the > same problems? Exception handling is a move away from fine grained handling. If in IOError is raised by a parser, I don't need to know at exactly which line the error occured. All I need to know is that the file is somehow unreadable; and that is why the parser failed. Therefore, none of the parser code should be handling IOError because it is being handled higher up in the stack. Since I expected that the parser might have problemes reading files, for problems that have nothing to do with my code, I explicity catch that error if it occurs. I am not expecting an IndexError from the parser and I don't bother to catch it. If the parser code does raise an IndexError, then my program crashes and I know that I have a bug in the parsing code. The call trace will tell me where that error occurs. I can watch that section of code in debugger to find out exactly what went wrong. > Actually return values of functions which I write myself can be as > specific and to the point. I could make it as fuzzy or as precise as I > like. This is no doubt, something that I could emulate with an exception > as well, but only make it slightly more complex with no obvious benefit. You seem to be making it complex because you are still trying to be too fine grained in handling each exception where it occurs as opposed to handing where the logic makes sense that it should be handled and because you are trying to code too defensively against your own code. Exception handling does require a different focus from handling errors from return values alone. > As I said before, the way exceptions are caught seem to me to be the most > confusing bit. Non-atomic operations always worry me. What if my function > which is wrapped inside a try block has two different statements that > raised the same exception but for different reasons? With error handling > I could probably handle it right below the statement which was called and > thus reduce the problem??? If you are having that issue, then you are likely placing the try blocks at too low of a level in your code. In general you will find that most systems have a gateway function as an entry point to the system. If there is not one already, then create such a function in you code. The parse function in my code above would be an example of such a gateway function. Beneath that function, you don't need to know exactly where the error occured, you just need to know the nature of the error and have general error handling procedures for each kind of error that you expect might occur. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Harishankar writes: > There are some reasons why I hate exceptions but that is a different > topic. However, in short I can say that personally: > > 1. I hate try blocks which add complexity to the code when none is > needed. Try blocks make code much more unreadable in my view and I use it > only for the built-in exceptions when absolutely needed. Very little code actually needs `try' blocks. > 2. I prefer the less irksome True or False to do error checking. > Exceptions seem too heavyweight for simple problems. Just write simple programs as if errors never happen; if an exception is raised, the program prints a vaguely useful message and exits. Besides, this complaint is incoherent. One needs at least as much structure to check an error code as to catch an exception. > 3. Philosophically I think exception handling is the wrong approach to > error management. There are better ways to handle errors than Python's exception system. Passing error codes around manually is most definitely not one of them. (One of the main reasons I ditched Perl in favour of Python is the former's insistence on returning error codes for I/O and system calls.) -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 15:53:49 +, Tim Harig wrote: > If you are using exceptions to try to catch bug then you are using them > improperly. Exceptions (with the exception (no pun intended) of > AssertionError) are designed to catch error conditions, not bugs. I agree. But more specifically some exceptions seem too broad to catch specific errors that occur in MY code rather than in a system call or a library call. Also writing my own exception objects and raising exceptions seem to add too much of complexity to what is essentially a simple problem. This is what I was trying to explain. > Actually, finer grained error handling commonly covers up bugs. If you > want to find bugs, you want to make the program prone to crashing if a > bug is present. It is all too easy to accidently mistake the return > value of a function as error condition and handle it rather the letting > the program crash. By separating the results from the transmission of > error conditions (in effect taking error conditions out of band) then > you make it much harder to make such a mistake because you have to > explicity indicate which error conditions your code is capable of > generating. Doesn't the same finer grained exception mechanism make it prone to the same problems? Actually return values of functions which I write myself can be as specific and to the point. I could make it as fuzzy or as precise as I like. This is no doubt, something that I could emulate with an exception as well, but only make it slightly more complex with no obvious benefit. As I said before, the way exceptions are caught seem to me to be the most confusing bit. Non-atomic operations always worry me. What if my function which is wrapped inside a try block has two different statements that raised the same exception but for different reasons? With error handling I could probably handle it right below the statement which was called and thus reduce the problem??? -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Harishankar wrote: > I understand that the error vs exception debate is quite a big one in the > programming community as a whole and I don't consider myself very Actually, I thought that debate was resolved years ago. I cannot think of a single recently developed programming language that does not provide exception handling mechanisms because they have been proven more reliable. > Python. I do understand both sides of the issue. Exceptions seem to be > generally more reliable but I feel they add a lot of complexity > particular when a lot of code is placed in a try block. Lines of code is one measure of complexity. Each line of code has a small chance of containing a bug. The more lines of code that you have, then the more likely that one of them contains a bug. Exceptions, by placing error handling code in fewer places, requires much fewer lines of code then requiring error handling code after each call that might produce an error condition. The operations of propogating an error up to the higher level logic of the program is another measure. In languages without exception handling, careful planning is needed to pass error conditions up through the call stack until they reach a high enough level in the logic that decisions can be made about how to handle them. Even further planning must be taken so that when the error condition reaches level where it needs to be handled, that enough information about the error is present to know exactly what went wrong so that it can figure out what to do about it. This usually involves using globals like errorno to pass out of band information about the error. Sometimes you even need to know about how the error affect intermediate levels, did the intermediate code attempt to handle the condtion and fail? The Openssl error handling system, that creates an error logging chain is an example of just how complex this can become. You gain all of this functionality automatically through exception mechanisms; without all of the complexity. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 07:35:18 -0800, Stephen Hansen wrote: > Exceptions aren't about "error management"; they are about exceptional > conditions: some are errors, others are entirely normal situations you > know are going to happen (such as reaching the end of a sequence as you > iterate over it: that's not an error, but it is special). To be > philosophically opposed to them seems to me to be philosophically in > favor of race conditions. Maybe I worded that part wrongly. Of course I get that error handling is only a part of exception mechanism. I agree that the built-in exceptions are useful but I prefer most times not to catch them. :-) > ? How do they destroy clarity or add clutter, since presumably you have > to deal with that "False" in some way with logical structure -- which > always does whitespace in Python. If not immediately, then up the call > stack (which seems to imply you should just not use a try/except and let > the exception unwind the stack to wherever in your code someone wants to > deal with it). The reason why I said they remove clarity is because it's not always obvious at which point the exception may be raised. In other words, within a try block there may be multiple statements that generate the exception. Of course, as I said before, one way would be to wrap single statements with the try block and avoid this issue. > > if is_correct(): > result = do_thing() > else: > do_error_handling() > > try: > result = do_thing() > except KeyError: > do_error_handling() Of course, to me the if statement would make more sense because I immediately figure out the exact condition being tested against while the exception object is not always so clear and maybe ambiguous in some cases. Also if that same type of exception is raised by another statement within a function that is called within the try block then it would be handled by the same except block right? This is where it gets a bit confusing to me and the flow of code is not always obvious. That's why I prefer atomic error handling where I know exactly which part of the code led to the result. > And as an aside, the more statements one puts into a try/except block: > and the more complicated a statement at that-- the more likely it is > they are going to mess up and do something Wrong. > > Now, all that said: sure, in some situations I do prefer the "check > first" style of programming where exceptions don't end up being used. > Its not *wrong* to return False on an "error condition": its going > against the grain, though, and makes your code harder to deal with > long-term if only because now there's two separate mechanisms that > "errors" happen in it. I realize that it is impossible for me to avoid exception mechanism myself. So I restrict it only to situations where I cannot avoid it (e.g. inbuilt exceptions in some cases where I want to handle it myself) > > You can't totally do away with exceptions in Python, even if you try > very hard. So with that in mind, IMHO, the best approach is to just... > get over it, and learn to appreciate them :) Finding it hard to appreciate exceptions myself. But I am used to thinking linearly. A piece of code which does not explain itself in the most obvious way even if I wrote it always worries me. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Harishankar wrote: > I am also wary of using larger catch-all try blocks or try blocks with > multiple exception exits (which seem to make tracking subtle bugs > harder). I prefer the philosophy of dealing with errors immediately as If you are using exceptions to try to catch bug then you are using them improperly. Exceptions (with the exception (no pun intended) of AssertionError) are designed to catch error conditions, not bugs. > harder). I prefer the philosophy of dealing with errors immediately as > they arise, rather than delegate them to exception mechanism. Of course, > I could wrap single statements in try blocks, but that makes the code > even messier without any significant benefits. Actually, finer grained error handling commonly covers up bugs. If you want to find bugs, you want to make the program prone to crashing if a bug is present. It is all too easy to accidently mistake the return value of a function as error condition and handle it rather the letting the program crash. By separating the results from the transmission of error conditions (in effect taking error conditions out of band) then you make it much harder to make such a mistake because you have to explicity indicate which error conditions your code is capable of generating. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 15:25:55 +, Tim Harig wrote: >... >... > > Perhaps you should take a look at how Erlang appoaches exception > handling. Being message passing and concurrency oriented, Erlang > encourages ignoring error conditions within worker processes. Errors > instead cause the worker processes to be killed and a supervisory > process is notified, by message, so that it can handle the error and > respawn the worker process. Since it doesn't use try/exept blocks, > maybe that will be more to your liking. Thanks for the reply. I understand that the error vs exception debate is quite a big one in the programming community as a whole and I don't consider myself very knowledgeable in these issues. However, I will try to approach this with an open mind and see whether I can work with exceptions comfortably in Python. I do understand both sides of the issue. Exceptions seem to be generally more reliable but I feel they add a lot of complexity particular when a lot of code is placed in a try block. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/10 6:56 AM, Harishankar wrote: > On Thu, 02 Dec 2010 08:44:11 -0600, Tim Chase wrote: > >> On 12/02/2010 08:18 AM, Harishankar wrote: >>> Here I'm using it to compare the result of a function where I >>> specifically return False on error condition, >> >> This sounds exactly like the reason to use exceptions...you have an >> exceptional error condition. >> >> -tkc > > There are some reasons why I hate exceptions but that is a different > topic. However, in short I can say that personally: To each his/her own, of course; but -- > 3. Philosophically I think exception handling is the wrong approach to > error management. Exceptions aren't about "error management"; they are about exceptional conditions: some are errors, others are entirely normal situations you know are going to happen (such as reaching the end of a sequence as you iterate over it: that's not an error, but it is special). To be philosophically opposed to them seems to me to be philosophically in favor of race conditions. > I have never grown up programming with exceptions in C > and I couldn't pick up the habit with python either. Did I mention that I > detest try blocks? try blocks seem ugly and destroy code clarity at least > in my view. And enclosing single statements under separate try blocks > seem to add a lot of clutter. ? How do they destroy clarity or add clutter, since presumably you have to deal with that "False" in some way with logical structure -- which always does whitespace in Python. If not immediately, then up the call stack (which seems to imply you should just not use a try/except and let the exception unwind the stack to wherever in your code someone wants to deal with it). if is_correct(): result = do_thing() else: do_error_handling() try: result = do_thing() except KeyError: do_error_handling() And as an aside, the more statements one puts into a try/except block: and the more complicated a statement at that-- the more likely it is they are going to mess up and do something Wrong. Now, all that said: sure, in some situations I do prefer the "check first" style of programming where exceptions don't end up being used. Its not *wrong* to return False on an "error condition": its going against the grain, though, and makes your code harder to deal with long-term if only because now there's two separate mechanisms that "errors" happen in it. You can't totally do away with exceptions in Python, even if you try very hard. So with that in mind, IMHO, the best approach is to just... get over it, and learn to appreciate them :) But, to each his or her own. :) -- Stephen Hansen ... Also: Ixokai ... Mail: me+list/python (AT) ixokai (DOT) io ... Blog: http://meh.ixokai.io/ signature.asc Description: OpenPGP digital signature -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Steve Holden wrote: > On 12/2/2010 9:13 AM, Harishankar wrote: >> >> if not result: >> # error condition >> >> Now above I first realized that the function can also return an empty >> list under some conditions and so changed it to >> >> if result == False: >> # error condition >> >> >> But now I realize that it's better to use "is" >> >> if result is False: >> # error condition >> >> That is how my problem arose. > > Did you think about using exceptions to handle exceptional conditions? > If you are new to Python it may not be the obvious soltuion, but it can > greatly simplify program logic. If you're not used to using exceptions it may at first seem like they take extra effort to use. But usually, in the end, they end up being less work (and more importantly easier to read and less bugs). -- Grant Edwards grant.b.edwardsYow! He is the MELBA-BEING at ... the ANGEL CAKE gmail.com... XEROX him ... XEROX him -- -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 10:19:35 -0500, Steve Holden wrote: > On 12/2/2010 9:13 AM, Harishankar wrote: >> On Thu, 02 Dec 2010 22:19:25 +1100, Ben Finney wrote: >> >>> More details of the problem you're trying to solve would help with >>> giving specific advice. >> >> I'm writing functions with multiple points of failure exits. I use >> return False as a way to flag the error condition rather than raising >> exceptions. But under certain circumstances, the function can also >> return empty lists which equate to false when using the condition like: >> >> # myfunction () can return a list of tuples, but can also return an >> empty # list under certain conditions since it's query a database and >> the result # can be empty also >> >> result = myfunction (vars) >> >> if not result: >> # error condition >> >> Now above I first realized that the function can also return an empty >> list under some conditions and so changed it to >> >> if result == False: >> # error condition >> >> >> But now I realize that it's better to use "is" >> >> if result is False: >> # error condition >> >> That is how my problem arose. >> > Did you think about using exceptions to handle exceptional conditions? > If you are new to Python it may not be the obvious soltuion, but it can > greatly simplify program logic. > > regards > Steve I am not new to Python but I am not a fan of exceptions either. I prefer to avoid writing my own exceptions because it feels too heavy and clunky for simple error checking. Most times I find simple error checking ample for my purposes. Of course, I use the built-in exception objects when I have no choice, but I hate try blocks. They add clunkiness to code and besides exception objects seem to be fairly heavy-duty for simple error conditions where a true/false flag would probably suffice. I am also wary of using larger catch-all try blocks or try blocks with multiple exception exits (which seem to make tracking subtle bugs harder). I prefer the philosophy of dealing with errors immediately as they arise, rather than delegate them to exception mechanism. Of course, I could wrap single statements in try blocks, but that makes the code even messier without any significant benefits. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 2010-12-02, Harishankar wrote: > There are some reasons why I hate exceptions but that is a different > topic. However, in short I can say that personally: > > 1. I hate try blocks which add complexity to the code when none is > needed. Try blocks make code much more unreadable in my view and I use it > only for the built-in exceptions when absolutely needed. Actually, exceptions remove a ton of complexity and almost universally remove a ton of redundant error checking code. Second, they aleviate a ton of design complexity about designing a clean and unified method of error handling throughout the program. Using exceptions, the only real questions are where to handle various errors. It is a godsend for having to clean up intermediary results when an error occurs as part of a complex set of dependant sequential operations. > 2. I prefer the less irksome True or False to do error checking. > Exceptions seem too heavyweight for simple problems. Error handling in C huge source of bugs. First, error handling code is scattered throughout the codebase and second it is hard to test the error handling code for a number of failures. Being able to raise exceptions within your test code makes it much easier to write tests capable of detecting error handling bugs. > 3. Philosophically I think exception handling is the wrong approach to > error management. I have never grown up programming with exceptions in C > and I couldn't pick up the habit with python either. Did I mention that I > detest try blocks? try blocks seem ugly and destroy code clarity at least > in my view. And enclosing single statements under separate try blocks > seem to add a lot of clutter. Perhaps you should take a look at how Erlang appoaches exception handling. Being message passing and concurrency oriented, Erlang encourages ignoring error conditions within worker processes. Errors instead cause the worker processes to be killed and a supervisory process is notified, by message, so that it can handle the error and respawn the worker process. Since it doesn't use try/exept blocks, maybe that will be more to your liking. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 9:56 AM, Harishankar wrote: > 3. Philosophically I think exception handling is the wrong approach to > error management. I have never grown up programming with exceptions in C > and I couldn't pick up the habit with python either. Did I mention that I > detest try blocks? try blocks seem ugly and destroy code clarity at least > in my view. And enclosing single statements under separate try blocks > seem to add a lot of clutter. Whereas lots of nested if statements to test that multiple errors have all not occurred is a model of clarity? This sounds to me like a prejudice that will harm your Python development. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/2010 9:13 AM, Harishankar wrote: > On Thu, 02 Dec 2010 22:19:25 +1100, Ben Finney wrote: > >> More details of the problem you're trying to solve would help with >> giving specific advice. > > I'm writing functions with multiple points of failure exits. I use return > False as a way to flag the error condition rather than raising > exceptions. But under certain circumstances, the function can also return > empty lists which equate to false when using the condition like: > > # myfunction () can return a list of tuples, but can also return an empty > # list under certain conditions since it's query a database and the result > # can be empty also > > result = myfunction (vars) > > if not result: > # error condition > > Now above I first realized that the function can also return an empty > list under some conditions and so changed it to > > if result == False: > # error condition > > > But now I realize that it's better to use "is" > > if result is False: > # error condition > > That is how my problem arose. > Did you think about using exceptions to handle exceptional conditions? If you are new to Python it may not be the obvious soltuion, but it can greatly simplify program logic. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 PyCon 2011 Atlanta March 9-17 http://us.pycon.org/ See Python Video! http://python.mirocommunity.org/ Holden Web LLC http://www.holdenweb.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 08:44:11 -0600, Tim Chase wrote: > On 12/02/2010 08:18 AM, Harishankar wrote: >> Here I'm using it to compare the result of a function where I >> specifically return False on error condition, > > This sounds exactly like the reason to use exceptions...you have an > exceptional error condition. > > -tkc There are some reasons why I hate exceptions but that is a different topic. However, in short I can say that personally: 1. I hate try blocks which add complexity to the code when none is needed. Try blocks make code much more unreadable in my view and I use it only for the built-in exceptions when absolutely needed. 2. I prefer the less irksome True or False to do error checking. Exceptions seem too heavyweight for simple problems. 3. Philosophically I think exception handling is the wrong approach to error management. I have never grown up programming with exceptions in C and I couldn't pick up the habit with python either. Did I mention that I detest try blocks? try blocks seem ugly and destroy code clarity at least in my view. And enclosing single statements under separate try blocks seem to add a lot of clutter. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/02/2010 08:18 AM, Harishankar wrote: Here I'm using it to compare the result of a function where I specifically return False on error condition, This sounds exactly like the reason to use exceptions...you have an exceptional error condition. -tkc -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 02:49:50 -0800, Stephen Hansen wrote: >... >... >... > * P.S. I'm not saying its never right to use "is" outside of The > Singletons. Just that its probably not, for most people, what they > actually should do in most code. There are numerous counter-examples, of > course. Its just a general guideline to follow. Until a need arises that > demonstrates otherwise. Here I'm using it to compare the result of a function where I specifically return False on error condition, so I think it's better I check it against the literal False rather than the fuzzy False produced by the boolean operation. I wouldn't do this in most situations though, but I did need to distinguish between the the empty list and False and using the broader form as in "if not a" did not work as expected. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 22:19:25 +1100, Ben Finney wrote: > More details of the problem you're trying to solve would help with > giving specific advice. I'm writing functions with multiple points of failure exits. I use return False as a way to flag the error condition rather than raising exceptions. But under certain circumstances, the function can also return empty lists which equate to false when using the condition like: # myfunction () can return a list of tuples, but can also return an empty # list under certain conditions since it's query a database and the result # can be empty also result = myfunction (vars) if not result: # error condition Now above I first realized that the function can also return an empty list under some conditions and so changed it to if result == False: # error condition But now I realize that it's better to use "is" if result is False: # error condition That is how my problem arose. - Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Harishankar writes: > When I run pychecker through my modules I get the message that > comparisons with "False" is not necessary and that it might yield > unexpected results. Good advice. > Yet in some situations I need to specifically check whether False was > returned or None was returned. Why is comparison with False so bad? Because it's almost always unnecessary and can yield unexpected results :-) In other words, the only purpose of the ‘bool’ type is to have values explicitly designed for testing in Boolean conditions. Comparing them to the literals is a code smell — indicating a poor design. > # example code which matches both False and None > if not var: > # do something Can you give a specific real-world example of why this is not good enough? It's likely we can suggest better ways of achieving the broader purpose. > So how do you get around this? My functions return False and None > under different circumstances. Usually it is None that will be the special case, so it's usually better to write something like:: result = foo() if result is None: # do special things But that's just one possibility, and might not apply in your use case. > Should I raise exceptions instead? I feel it's unnecessary clutter to > use exceptions unless absolutely no other solution is available and > yet I have doubts about the "False" value. More details of the problem you're trying to solve would help with giving specific advice. -- \ “I was sad because I had no shoes, until I met a man who had no | `\ feet. So I said, ‘Got any shoes you're not using?’” —Steven | _o__) Wright | Ben Finney -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On 12/2/10 2:02 AM, Harishankar wrote: > On Thu, 02 Dec 2010 00:15:42 -0800, Alice Bevan–McGregor wrote: >> The bool type is a subclass of int! (Run those lines in a Python >> interpreter to see. ;) >> >>> if var == False: >> >> if var is False: … > > So "var is False" is safer to use when I want to specifically check > whether var is set to False and not 0 or None? Equality is a somewhat fuzzy concept. By convention and habit, its usually fine and clear: but its still fuzzy and up to each individual object involved to answer the question of equality. Now, its generally suggested in Python to do fairly vague truth testing: "if x" and "if not x" as opposed to concepts like "if x == True" and "if x == False" because the former is broad but usually more correct, and the latter can lead to some unexpected semantics. But that doesn't mean you must never check if something is False or True: there are times when you really do want or need to see if _False_ is what's being returned, or _True_, or _None_. In this case, use "is", yes, indeed. The "is" operator checks absolute object identity, and so is how you should do that check in cases where you want to test the distinction between "Is it /False/, or just something false-ish or not-true or nothing-ish?" Generally speaking in Python, you usually want to do tests as "if x" or "if not x". But sometimes you need to know if "x" is a specific singleton value: True, False or None. In that case, its okay to do "if x is True", "if x is False" or "if x is None". But you should only do that after the simple test is deemed inappropriate in your API or situation. And-- here's the rub-- while "is" is absolutely OK and right for you to use to test if an object is one of those singletons, its *probably* NOT what you want to do in any other situation*. Outside of the True/False/None singletons, and places where you're doing some special OOP-stuff, you almost certainly don't want to use 'is', but use equality checking (even if its fuzzy, because its fuzzy) instead. This demonstrates why "is" should be avoided except when in those singleton situations (except when you need to, of course): >>> a = 2 >>> b = 2 >>> a is b True >>> a == b True >>> a = 2 >>> b = 2 >>> a is b False >>> a == b True (If you're wondering why that's happening: Python makes very little in the way of promises with regard to object identity. It may choose to make a whole new int object of value 2 every time you type 2, or use the same old int object each time: sure, presently it tends to only share "small" integers for re-use, but that's not a promise, not a documented feature, but a function of the current implementation. It could happen tomorrow, in theory, that where a = 1; b = 1; become the same object as far as "is" is concerned even though today they are different... "is" should only be used in situations where you care about absolute object identity, not *value*.) -- Stephen Hansen ... Also: Ixokai ... Mail: me+list/python (AT) ixokai (DOT) io ... Blog: http://meh.ixokai.io/ * P.S. I'm not saying its never right to use "is" outside of The Singletons. Just that its probably not, for most people, what they actually should do in most code. There are numerous counter-examples, of course. Its just a general guideline to follow. Until a need arises that demonstrates otherwise. signature.asc Description: OpenPGP digital signature -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 09:58:18 +, Nobody wrote: > If you want to test specifically for True, False or None, use "is" > rather than an equality check. This eliminates the warning and doesn't > risk misleading someone reading the code. Thanks so much for this very specific answer. I guess "is" is what I am looking for. :-) -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 00:15:42 -0800, Alice Bevan–McGregor wrote: > Howdy! Good day to you! > (False == 0) is True > (True == 1) is True I see. Thanks for this. I suspected this, but wasn't sure. > The bool type is a subclass of int! (Run those lines in a Python > interpreter to see. ;) > >> if var == False: > > if var is False: … So "var is False" is safer to use when I want to specifically check whether var is set to False and not 0 or None? > If you want to check not just for value equivelance (False == 0) but > literal type, use the "is" comparator. "is" checks, and others correct > me if I'm wrong, the literal memory address of an object against > another. E.g. False, being a singleton, will always have the same > memory address. (This is true of CPython, possibly not of Python > implementations like Jython or IronPython.) Using "is" will be > effective for checking for literal None as well. Thanks, it makes sense to me now. Literal equivalence is what I was looking for. I didn't quite understand whether == achieved this or not. Now I guess I know. > > When ever I need to test for None, I always use the "is" comparator. > It's also more English-like. (None, evaluating to False when using > '==', is useful when all you care about is having a blank default value, > for example.) Yes, but in my function I don't want to confuse False with 0 or anything else except False. Thanks again for explaining this clearly. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
On Thu, 02 Dec 2010 07:28:30 +, Harishankar wrote: > When I run pychecker through my modules I get the message that > comparisons with "False" is not necessary and that it might yield > unexpected results. > > Yet in some situations I need to specifically check whether False was > returned or None was returned. Why is comparison with False so bad? The behaviour may be counterintuitive. One might expect that "x == False" is equivalent to "not x". Sometimes it is, sometimes it isn't. E.g. 0 and 0.0 are equal to False and are equivalent to False when converted to booleans: > 0 == False True > not 0 True > 0.0 == False True > not 0.0 True [], "" and None aren't equal to False but are equivalent to False when converted to booleans: > [] == False False > not [] True > "" == False False > not "" True > None == False False > not None True The boolean conversions are what's relevant for "if x ...", "while x ...", etc. If you want to test specifically for True, False or None, use "is" rather than an equality check. This eliminates the warning and doesn't risk misleading someone reading the code. -- http://mail.python.org/mailman/listinfo/python-list
Re: Comparison with False - something I don't understand
Howdy! When I run pychecker through my modules I get the message that comparisons with "False" is not necessary and that it might yield unexpected results. Comparisons against False -are- dangerous, demonstrated below. Yet in some situations I need to specifically check whether False was returned or None was returned. Why is comparison with False so bad? (False == 0) is True (True == 1) is True The bool type is a subclass of int! (Run those lines in a Python interpreter to see. ;) if var == False: if var is False: … So how do you get around this? My functions return False and None under different circumstances. Should I raise exceptions instead? I feel it's unnecessary clutter to use exceptions unless absolutely no other solution is available and yet I have doubts about the "False" value. If you want to check not just for value equivelance (False == 0) but literal type, use the "is" comparator. "is" checks, and others correct me if I'm wrong, the literal memory address of an object against another. E.g. False, being a singleton, will always have the same memory address. (This is true of CPython, possibly not of Python implementations like Jython or IronPython.) Using "is" will be effective for checking for literal None as well. When ever I need to test for None, I always use the "is" comparator. It's also more English-like. (None, evaluating to False when using '==', is useful when all you care about is having a blank default value, for example.) — Alice. -- http://mail.python.org/mailman/listinfo/python-list
Comparison with False - something I don't understand
When I run pychecker through my modules I get the message that comparisons with "False" is not necessary and that it might yield unexpected results. Yet in some situations I need to specifically check whether False was returned or None was returned. Why is comparison with False so bad? # example code which matches both False and None if not var: # do something # specifically check if False is returned # I don't want None if var == False: # do something So how do you get around this? My functions return False and None under different circumstances. Should I raise exceptions instead? I feel it's unnecessary clutter to use exceptions unless absolutely no other solution is available and yet I have doubts about the "False" value. -- Harishankar (http://harishankar.org http://lawstudentscommunity.com) -- http://mail.python.org/mailman/listinfo/python-list