Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Taming The Switch-Statement
Date: Tue, 20 Oct 2026 16:10:48 -0700
Organization: A noiseless patient Spider
Lines: 134
Message-ID: <86pkx4nf2f.fsf@linuxsc.com>
References: <119qf6l$2rmg3$1@dont-email.me> <11afvqt$2kloc$1@dont-email.me> <11ag37o$2ln0a$1@dont-email.me> <11agbsh$2pbk7$1@dont-email.me> <11aggaq$2qqh9$1@dont-email.me> <11agils$2s3tg$1@dont-email.me> <11agv1t$30q22$2@kst.eternal-september.org> <20261012220256.00003d07@yahoo.com> <11ajb95$3t8jj$1@dont-email.me> <20261012223144.00000f95@yahoo.com> <11akm9q$29tpl$1@paganini.bofh.team> <11am99u$ul56$2@dont-email.me> <11atfif$38b7p$1@paganini.bofh.team> <8633u3pwwd.fsf@linuxsc.com> <11b6bsj$ctsd$1@paganini.bofh.team>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Date: Tue, 20 Oct 2026 23:10:53 +0000 (UTC)
Injection-Info: dont-email.me; logging-data="3641200"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+calQ2+oS4XGZ65E/DtaqBkSDWqrfG/5w="; posting-host="9df08f8720e7d6c5f9792d5f5cf06aad"
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:DbWGhxiJXrXIcMZBFMu2hNdj9Bs= sha1:h7w4r0Loos0Tr2zVmuhgcK0b30w= sha256:odrQb/EDPCOrR3UwABY0o0bsZAmXBorMMQD99tkvq3g= sha1:WTXZaEPyZ4uRqjYmsgfwiFtkXDA= sha256:1MIl49bc5S1Eaopv84JHvAJQoZWegDDG+Phb6XprEKM=
Xref: csiph.com comp.lang.c:403392
antispam@fricas.org (Waldek Hebisch) writes:
> Tim Rentsch wrote:
>
>> antispam@fricas.org (Waldek Hebisch) writes:
>>
>>> Lawrence D?Oliveiro wrote:
>>>
>>>> On Tue, 13 Oct 2026 07:23:40 -0000 (UTC), Waldek Hebisch wrote:
>>>>
>>>>> So what those counts indicate: majority of loops is simple, that is
>>>>> have no early exit. Vast majority of early exits is done via
>>>>> 'return'.
>>>>
>>>> My experience in my own C code is quite the opposite. Lots of loops
>>>> have exits in the middle, leading me to use forms like ?for (;;)?. I
>>>> also try to avoid putting ?return? anywhere other than the end of a
>>>> function, to make it easier to see the flow of control.
>>>
>>> Well, usually there is a lot of loops. Those with exit in the
>>> middle are still significant.
>>>
>>> Concernig 'return', having it in place where all work inside function
>>> is done help me to see flow control and avoids complications. In
>>> case of search functions it means return from the middle of the loop.
>>> IMO possible alternatives like flag variables or break and retrun
>>> after loop are worse.
>>
>> I rarely use 'break' to exit a loop. Part of this is that I try to
>> write standard loops so that they complete as part of the loop test
>> (i.e., in while() or for() control expressions). That isn't the
>> whole story though so let me talk about 'return'.
>
> I counted various constructs in a small suite of 2 programs (1306
> lines in 3 files). There are 4 breaks outside switches and 32
> loops in total. My gut feeling is that this proportion is
> reasonable close to typical in my code. For comparison, there
> are 67 functions and 70 'if'-s.
Probably that is close to what I see for my own code, if we
count 'return' out of a loop.
>> Most of the functions I write have exactly one return, at the end of
>> the function. I estimate this pattern accounts for around 85% of
>> all functions, let's say plus or minus 5%.
>
> In code above about half of functions is 'void' and there are 34
> explicit returns (of which at least 2 are early returns).
I almost never use void functions. I'm used to a functional style,
and it's natural to return something in almost all cases.
>> Sometimes functions have early returns for errors or exceptional
>> conditions.
>
> Code above contains 16 occurences of 'exit(1)'. One of those is
> in a macro that is used 10 times, so actually there are 25 places
> which call 'exit(1)'. That is related to the programs being
> simple utilities, there is no attempt to error recovery, on error
> programs simply print error message and exit.
okay. I don't use exit() often but I have no problem with that.
>> Early returns are easily seen to lie outside the main
>> body of function processing so they don't interfere with
>> understanding what the rest of the function is doing or how it
>> works.
>>
>> A fairly common sub-pattern are functions most of whose body is a
>> switch() statement, with all of the switch() cases being a simple
>> return.
>
> Code above has 2 switches, both are in parsing functions, where
> cases either move to next state or signal error. Parsing functions
> also open file and close it when finished and return data structure
> with parsed info.
In other kinds of code I might use switch() more often. Maybe I
can try putting together a small application where switch() is more
likely and see what I get.
>> It does sometimes happen that a function will have a loop with a
>> return in the middle, and also a return at the end for what to do if
>> the loop terminates. To me having an in-loop return looks better
>> than using an assignment and a break.
>>
>> A fairly rare but important pattern is what I might call vectoring
>> or decomposition. Here the function body serves to distinguish and
>> separate out different regimes of subprocessing. To continue
>> processing in a particular regime, a return is used not to directly
>> yield a value but rather to call a further function to handle that
>> sub-domain. The benefit here is both to keep function bodies small
>> and to allow re-use of commonly called sub-functions.
>>
>> Two aspects are important for having these different styles work
>> together. One is that it's easy to distinguish the different kinds
>> of patterns, and by far the most simple pattern is the most common.
>> The other is to be sure to keep function bodies small. Keeping
>> function bodies small goes a long way in making them easy to
>> understand, which obviously is a key property in writing good code.
>> Also keeping function bodies small effectively prevents mixing
>> different styles in a single function, serving to reinforce point
>> one.
>
> I think that in general my C code has similar characteristics.
Yes it sounds that way.
> But
> let me note that while I have a lot of small functions, I also have
> some which are bigger. I suspect that 10% or more of my code is
> in functions that are bigger then 30 lines. Such functions
> frequently have several variables and there is setup stage to
> initialize things, actual processing and final part (cleanups,
> possibly extraction of result). Stages are clearly sepatated
> by their position inside function, OTOH are strongly coupled due
> to use of variables. My feeling here is that in case of strongly
> coupled code with no reusable parts keeping it inside single
> function is more managable than trying to split it into smaller
> functions.
It's natural for me not to let functions get too large, which means
more than about 60 lines of code. But beyond that wanting to write
small functions doesn't mean only tiny functions. My "10% or more"
function size may be a little smaller than yours, but not much
smaller. Also I observe empirically an interesting property, which
is that if we multiply the number of functions of size N by N, the
result is roughly constant across the range of function sizes. So
for example if there are three functions whose bodies have 50 lines
then there are roughly 50 functions whose bodies have three lines.
And that holds approximately across the whole range of function
sizes (with a standard deviation about half the average). So there
are lots of little functions but also functions of sizes in the
20s, 30s, 40s and 50s. Does that sound similar to your own code?