• on the importance of exceptions

    From Meredith Montgomery@21:1/5 to All on Mon Sep 5 19:59:28 2022
    I'm trying to show people that exceptions are a very nice thing to have
    when it comes to detecting when something went awry somewhere. I'd like
    a real-world case, though.

    Here's what I'm sort of coming up with --- given my limited experience
    and imagination. Below, you have f calling g caling h calling j which
    returns True or False based on a random thing. (This simulates a task
    that sometimes succeeds and sometimes fails.) If while at f() I want to
    know what happened at j(), I'm going to have to propagate that
    information upwards through the execution stack. I can't do that right
    now: I'd have to change f, g and h.

    --8<---------------cut here---------------start------------->8---
    from random import randint

    def f():
    g()

    def g():
    h()

    def h():
    if j():
    print("I got a 2.")
    else:
    print("I got a 1.")

    def j():
    return randint(1,2) == 2
    --8<---------------cut here---------------end--------------->8---

    If instead of that, j() would be raising an exception when it fails,
    then all I only need to change f() to know what happens.

    I could replace j's test with opening a file, say. That would improve
    it a little. I'm sure you guys know excellent cases to show. Would you
    be so kind to share anything you might have in mind?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julio Di Egidio@21:1/5 to Meredith Montgomery on Mon Sep 5 16:30:32 2022
    On Tuesday, 6 September 2022 at 01:00:03 UTC+2, Meredith Montgomery wrote:

    I'm trying to show people that exceptions are a very nice thing to have

    Welcome to my kill-file.

    *Plonk*

    Julio

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Meredith Montgomery@21:1/5 to Meredith Montgomery on Mon Sep 5 23:15:15 2022
    Meredith Montgomery <mmontgomery@levado.to> writes:

    I'm trying to show people that exceptions are a very nice thing to have
    when it comes to detecting when something went awry somewhere. I'd like
    a real-world case, though.

    Here's my contribution. I want to handle all errors in main() and the
    real job is done in does_a_job(), which, in turns, needs to delegate
    tasks to those other procedures that fail sometimes.

    It's does_a_job() that /must/ distinguish the error codes because errors
    come in as False from both opens_file() and reads_file(). So the checks
    must be done both in does_a_job() and in main(). (We also notice that does_a_job() has a return-type that's a union (sometimes an integer,
    sometimes a string), which makes distinguishing error code and success a
    bit harder.)

    --8<---------------cut here---------------start------------->8---
    from random import randint

    def main():
    r, data = does_a_job()
    if r < 0:
    if r == -1:
    print("Fatal. Could not open file.")
    return None
    if r == -2:
    print("Fatal. Could not read file")
    return None
    print(f"Great! We got the data: ``{r}''.")

    def does_a_job():
    okay = opens_file()
    if not okay:
    return -1
    okay, data = reads_file()
    if not okay:
    return -2
    closes_file()
    return data

    def open_file(): # Opens okay with probability 80%
    return randint(1,10) <= 8

    def read_file(): # Reads okay with probability 50%
    return randint(1,10) <= 5, "data I am"

    def closes_file(): # Works with probability 1
    return True
    --8<---------------cut here---------------end--------------->8---

    If we could give the program a final destination at does_a_job(), the
    job would be easier. But all we want to do in does_a_job() is to
    propagate the error conditions upwards to main() to really decide what
    to do. Exceptions lets us do that with a cleaner version.

    --8<---------------cut here---------------start------------->8---
    from random import randint

    def main():
    try:
    data = does_a_job()
    except FileNotFoundError:
    print("Fatal. Could not open file.")
    except MemoryError:
    print("Fatal. Could not read file")
    else:
    print(f"Great! We got the data: ``{data}''.")

    def does_a_job():
    open_file()
    data = reads_file()
    close_file()
    return data

    def open_file(): # Opens okay with probability 80%
    if randint(1,10) <= 8:
    return True
    raise FileNotFoundError("Sorry: the file system is /so/ busy right now.")

    def reads_file(): # Reads okay with probability 50%
    if randint(1,10) <= 5:
    return "data I am"
    raise MemoryError("Sorry: not enough memory for /all/ this data.")

    def close_file(): # Works with probability 1
    return True
    --8<---------------cut here---------------end--------------->8---

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)