Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!samsung!aplcen!haven!mimsy!chris From: chris@mimsy.umd.edu (Chris Torek) Newsgroups: comp.lang.misc Subject: Re: problems/risks due to programming language, stories requested Message-ID: <23076@mimsy.umd.edu> Date: 14 Mar 90 00:27:26 GMT References: <1004@micropen> <8218@hubcap.clemson.edu> <1771@awdprime.UUCP> <879@enea.se> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 112 [nb: I am not going to see followups, since comp.lang.misc is too far down my .newsrc and I never get there.] In article <879@enea.se> sommar@enea.se (Erland Sommarskog) writes: >Cross you heart, how often in practical programming do you write >[code using C's `fall through' cases]? And how often compared to >normal switch statements where an easily elided break would introduce >a simple bug? Well, just for statistics, there is one (count 'em one :-) ) such switch in the 4.3BSD-tahoe machine independent kernel source, in tty_pty.c, in the ptcselect() routine. (The code appears below.) This is 1 out of 73 C source files in my /sys/kern directory (which has more files than standard 4.3BSD-tahoe) and a few lines out of 30,000. (This includes the ufs code, which has not yet moved out to /sys/ufs on my system.) There are several more in the unibus code, e.g., in ts.c and uba.c; there is one in netinet/in.c and one in netimp/if_imp.c. Caveat: these were found via `egrep FALL *.c', to find those labelled /* FALLTHROUGH */ or /* FALL THROUGH */ or /* FALLTHRU */ or /* FALL THRU */ and it may have missed some. All in all, it does seem rather backward that the usual need---to break after executable code following a case---is not the default. The logical alternative, however, has a pitfall: if one were to `tweak' the language so that `case' meant `break from previous case and enter new one if there was executable code before this one', then code of the form switch (foo) { case A: case B: frob_A_or_B(foo); case C: frob_C(foo); case D: case E: frob_D_or_E(foo); default: panic("bad foo"); } would act mysteriously if `frob_C(foo)' turned out to be a no-op and were later recoded as `#define frob_C(x) /* empty */'. In other words, all of a sudden, in addition to needing some construct to allow fall through (`goto' suffices here), we have to change `case' to allow multiple cases. No big deal perhaps, but what looked easy has become more complicated. On the other hand, the code shrinks a bit: switch (foo) { case A, B: frob_A_or_B(foo); case C: frob_C(foo); case D, E: frob_D_or_E(foo); default: panic("bad foo"); } Anyway, here is the fall-through code from /sys/kern/tty_pty.c (known as /sys/sys/tty_pty in the currently-available BSDs). switch (rw) { case FREAD: /* * Need to block timeouts (ttrstart). */ s = spltty(); if ((tp->t_state&TS_ISOPEN) && tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { splx(s); return (1); } splx(s); /* FALLTHROUGH */ case 0: /* exceptional */ if ((tp->t_state&TS_ISOPEN) && (pti->pt_flags&PF_PKT && pti->pt_send || pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) return (1); if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) pti->pt_flags |= PF_RCOLL; else pti->pt_selr = u.u_procp; break; case FWRITE: if (tp->t_state&TS_ISOPEN) { if (pti->pt_flags & PF_REMOTE) { if (tp->t_canq.c_cc == 0) return (1); } else { if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) return (1); if (tp->t_canq.c_cc == 0 && (tp->t_flags & (RAW|CBREAK)) == 0) return (1); } } if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) pti->pt_flags |= PF_WCOLL; else pti->pt_selw = u.u_procp; break; } return (0); } Anyway, there is one data point. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris