Path: utzoo!attcan!uunet!husc6!think!ames!mailrus!uflorida!novavax!proxftl!bill
From: bill@proxftl.UUCP (T. William Wells)
Newsgroups: comp.misc
Subject: Re: Basics of Program Design
Summary: efficiency is the reward of the diligent
Message-ID: <430@proxftl.UUCP>
Date: 5 Jul 88 23:55:39 GMT
References: <901@td2cad.intel.com> <3061@rpp386.UUCP> <395@proxftl.UUCP> 
Distribution: na
Organization: Proximity Technology, Ft. Lauderdale
Lines: 114

In article , webber@porthos.rutgers.edu (Bob Webber) writes:
> > In the real world, most compilers do NOT deal with tail recursion,
>          ^^^^^^^^^^ -- what makes you think your world is real?

14 years of commercial programming, the last 5 almost exclusively
C. Languages used at least a year to earn paychecks,
chronologically: Fortran, Basic, various database languages,
COBOL, RPG, C.  Over a half a dozen assembly languages used for
commercial programming.  Recent projects: project leader for
improvements to a spelling checker for 6 (at the time) languages,
currently doing R&D and for a grammar checker.

Real enough?

> > it not often being very useful to do this for C programs.
>
> Well, there is a free, high quality C compiler for 68000-based systems
> and various others that does do tail recurision (i.e., gcc) among other
> things.  [However, it wouldn't catch this particular case -- perhaps
> that is why you aren't using it? ]

That's fine for 68000's (like the Sun I am working on) but not
for IBM-PC's (our secondary machines) nor for the 100+ compilers
our code is regularly compiled with. Relying on compilers to do
tail recursion optimization would be slitting our own throats.

>                                     Optimizations fall into two categories:
> those that handle the poor fit between language and architecture and those
> that save programmer time.  While for a language like SCHEME, this
> would be viewed as a language-related optimization, in a language like
> C it falls in the second category.

Sorry, but using purely tail recursive routines does not save
time for this programmer. Anywhere you would use tail recursion,
I'd automatically code a while loop.  (See below for why.) This
means that your optimization actually falls in a third category:
optimizations designed to let the programmer choose his own
personal coding style.  This does not apply to tail recursion
discovered by the optimizer, however.

Also, another real-world point: recursive routines in general
need to be used carefully, to avoid excess resource consumption.
As an example, I recently translated a rather complicated parsing
routine from SCHEME to C. In the translated version were several
recursive routines. One of the recursive routines was left alone,
the greatest depth of recursion was the length of a grammar rule
and removing the recursion would have been a real pain.  Another
got fixed (even though it required extensive recoding) because it
was not possible to bound the stack usage. Our customers WILL
NOT let us chew resources with wild abandon.

> > A perfectly good algorithm can be a BAD choice in the real
> > world.  Yes, the algorithm is "good", which is to say, it works
> > and is of the best possible order, but it is poorer than the
> > standard implementation since its constant factor is going to be
> > larger.
>
> Yes, you have learned the first lesson.  Let me introduce you to the
> second lesson: Not all code is executed the same amount of time.  Thus
> it is more important for some things to be fast than it is for others.
> Strlen does not make sense as a function to be optimizing the death out
> of.  After all, if it is used all that much -- why isn't it a macro?

Look buddy, I know both lessons. From the contents of your
posting, I'd say better than you. One of the things I do better
than damn near anyone else is make C programs go faster and get
smaller.

So here is a third lesson for you: try to make everything you do
as good as you can. The notion that a routine is only going to be
used a small fraction of the time is no excuse for sloppiness.
Even if the routines are only going to be used 1% of the time,
those damn little routines can end up eating much of your
program's run time.

To make this concrete, let me describe the profile output from a
typical program after I have finished with it: The first few
routines take about 5-10% of the execution time apiece.  The
remaining routines take less than a few percent apiece of the
execution time.  (This happens because I follow your second
lesson: I beat the execution time hogs down until they are no
longer hogs.)

If the coder of those small change routines was as sloppy as you
advocate, that sloppiness would result in many or most of those
trivial routines being slower. Since those routines, in
aggregate, make up a significant fraction of my program (from
the standpoint of execution time), that means that my program
will go significantly slower.

Here is another example. A program I had to work with (a C
version of the pattern generator for Knuth's hyphenator) spent
40% of its time in sscanf. There was NO GOOD REASON for
sscanf(buf, "%d %s", &n, &ptr) to take that long, other than
sloppy programming.  (I replaced the call with my own scanning
routines, the time spent in them was then 5% of the execution
time.) Perhaps someone else can give an example of a program
where strlen() did the same thing?

And a final point. You have encouraged sloppiness in writing
strlen() by justifying it with "that routine is never going to be
executed much anyway." Even granted that proposition you have
forgotten an important point. If you do not make it a habit to
write good code ALL THE TIME, that means two things: 1) Your code
will be generally less efficient than it could have been.  2)
When it comes time to write efficient code, you will not have
the experience needed to do it.

Learning is a cumulative process. This little bitty routine that
will not be executed much is as good a place for thinking about
efficiency as any other, and possibly better. Do it enough and
efficient coding becomes second nature. Then you will naturally
write efficient programs and as a matter of course will not do
stupid things like writing strlen() recursively.