Re: The Philosophy of Programming?

From: Edward G. Nilges (spinoza1111_at_yahoo.com)
Date: 02/15/04


Date: 14 Feb 2004 17:31:21 -0800

chiuk@cs.indiana.edu (Kenneth Chiu) wrote in message news:<c0kdkc$bmk$1@hood.uits.indiana.edu>...
> In article <f5dda427.0402132053.69df5ce0@posting.google.com>,
> Edward G. Nilges <spinoza1111@yahoo.com> wrote:
> >chiuk@cs.indiana.edu (Kenneth Chiu) wrote in message news:<c0h4o1$a4i$1@hood.uits.indiana.edu>...
> >> In article <f5dda427.0402121543.46a36235@posting.google.com>,
> >> Edward G. Nilges <spinoza1111@yahoo.com> wrote:
> >> >Thus a question in the philosophy of programming would be in fact
> >> >whether it is good praxis to sacrifice micro-efficiency for one less
> >> >Annoying Temporary Variable, which like The Man Who Came To Dinner, is
> >> >allocated, in many languages, on function entry and released on exit
> >> >(an effiency tax which has to be subtracted from the saving) and which
> >> >might be used at the wrong time when its state is out of date (a
> >> >maintainability tax).
> >>
> >> Just curious, could you give an example of this in C? Many
> >> modern compilers will produce the same code regardless of
> >> temporary variables.
> >
> >The ISO standard on vanilla automatic variables reads
> >
> > An object whose identifier is declared with no linkage
> > and without the storage-class specifier static has automatic
> > storage duration. For objects that do not have a variable
> > length array type, storage is guaranteed to be reserved for
> > a new instance of the object on each entry into the block
> > with which it is associated; the initial value of the object
> > is indeterminate. If an initialization is specified for the
> > object, it is performed each time the declaration is reached
> > in the execution of the block; otherwise, the value becomes
> > indeterminate each time the declaration is reached. Storage
> > for the object is no longer guaranteed to be reserved when
> > execution of the block ends in any way. (Entering an
> > enclosed block or calling a function suspends, but does not
> > end, execution of the current block.)
>
> But this is a semantic specification. A compiler is free to
> do anything it wants, as long as it preserves the semantics. From
> what I've seen of the generated code, temporary variables in
> C with most modern compilers results in negligible or zero
> cost.

You're talking only about one cost and that is cost to the CPU and the
memory.

You are neglecting my concern which is the psychological complexity of
the source code, I should have been clearer.

In my strlen example, deriving the strlen for a string known to be
bounded by the input console length in a function in the do condition
lowers the psychological complexity.

More generally, using expressions in place of temporary variables
lowers psychological complexity for most intelligent readers.

I agree that many programmers prefer to see temprary variables and I
propose that this is because their use of the temporary variable
paradigm, communicated to them by false authority, damaged them in
Dijkstra's sense, where he claims that early exposure to Basic damages
programming ability.

To me, the length of a string is something I should just have if I
have a string. However, in May 2002 when I downloaded Jacques Navia's
free compiler and coded in C after an interval of ten years, I had a
massive brain fart.

I forgot to keep foregrounded in my mind the reality that C doesn't
really have strings. It has arrays of numbers terminated by zero, and
you don't "have" strlen, which has to trundle to the end of the
string.

However, if C is at all a viable language, it should support brain
farts with at best slightly slower code and in this case it did. This
is why C, which itself was a brain fart, is still used.

You can build initial versions of code in a readable fashion, test
them, and then improve performance at the key places that need it.

>
> >
> >I'd said "in many languages" but I should have qualified what I said
> >as "many traditional languages".
> >
> >Languages with a traditional semantics, including Visual Basic before
> >.Net, allocated the set of variables in a procedure block but not a
> >finer grained block. The standard for C, and for the .Net languages,
> >is to allocate on entry to almost any block. This standard is obscured
> >by the fact that traditionally in languages like PL/I and C for that
> >matter, it has been considered best practice to allocate all the
> >variables before the first procedural command, and this "best"
> >practice obscures the difference between the two standards.
> >
> >In fact it might be best practice not to allocate all the variables
> >first but almost-just-in-time, and to the closest point-of-use that is
> >not inside a loop, the last avoiding potential reallocation.
> >
> >I don't understand what you mean by "most modern compilers will
> >produce the same code regardless of temporary variables."
>
> I was referring to code like:
>
> int foo(int a, int b, int c) {
> /* Use temp var. */
> int t = a*b;
> return c/t + t;
> }
>
> int goo(int a, int b, int c) {
> /* No temp var, but common sub-exprs. */
> return c/(a*b) + a*b;
> }
>
> Using gcc 3.2.2 and "gcc -S -O foo.c", it generates:
>
> .file "foo.c"
> .text
> .globl foo
> .type foo,@function
> foo:
> pushl %ebp
> movl %esp, %ebp
> subl $4, %esp
> movl 16(%ebp), %eax
> movl 12(%ebp), %edx
> movl 8(%ebp), %ecx
> imull %edx, %ecx
> cltd
> idivl %ecx
> addl %ecx, %eax
> leave
> ret
> .Lfe1:
> .size foo,.Lfe1-foo
> .globl goo
> .type goo,@function
> goo:
> pushl %ebp
> movl %esp, %ebp
> subl $4, %esp
> movl 16(%ebp), %eax
> movl 12(%ebp), %edx
> movl 8(%ebp), %ecx
> imull %edx, %ecx
> cltd
> idivl %ecx
> addl %ecx, %eax
> leave
> ret
> .Lfe2:
> .size goo,.Lfe2-goo
> .ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
>
> Note the same code for each function.

Same code: different psychological metrics.

I did say that there might be an efficiency tax and for this example,
there clearly is not.

But when you scale up to multiple temp variables across multiple
procedures the compiler will generate different code because the
optimizer probably won't be able to see common variables.

>
> >It is true
> >that optimizing compilers can even eliminate temporary variables but
> >surely different code will be compiled from
> >
> >for (intIndex1 = 1; intIndex1 < strlen(strInstring); intIndex++)
> >
> >as opposed to
> >
> >int intLameo = strlen(strInstring);
> >for (intIndex1 = 1; intIndex1 < intLameo; intIndex++)
> >
> >Optimizing compilers don't eliminate and can complicate these
> >considerations.
>
> In this case, the compiler won't produce the same code,
> because most won't be smart enough to recognize that the
> result of strlen() is a loop invariant. However, any decent
> compiler will use a register, and so there will be no
> allocation/deallocation cost. The version with the
> temporary variable will in fact be faster.

Excuse me, how many registers are their? If in the surrounding context
they are busy, there WILL be allocation and deallocation costs in the
form of save and restore!

>
> This code:
>
> #include <strings.h>
>
> void goo();
> void foo(const char *s) {
> int n = strlen(s);
> int i;
> for (i = 0; i < n; i++) {
> goo();
> }
> }
>
> results in this SPARC assembly code (I'm better at reading
> SPARC than x86, so I generated SPARC):
>
> ! 1 !#include <strings.h>
> ! 3 !void goo();
> ! 4 !void foo(const char *s) {
>
> .global foo
> foo:
> /* 000000 4 */ save %sp,-96,%sp
>
> ! 5 ! int n = strlen(s);
>
> /* 0x0004 5 */ call strlen ! params = %o0 ! Result = %o0
> /* 0x0008 4 */ or %g0,%i0,%o0
> /* Result of strlen() put into register %l0. */
> /* 0x000c 5 */ orcc %g0,%o0,%l0
>
> ! 6 ! int i;
> ! 7 ! for (i = 0; i < n; i++) {
>
> /* 0x0010 7 */ ble .L77000006
> /* 0x0014 */ or %g0,0,%l1
>
> ! 8 ! goo();
>
> .L77000003:
> /* 0x0018 8 */ call goo ! params = ! Result =
> /* 0x001c */ add %l1,1,%l1
> /* 0x0020 */ cmp %l1,%l0
> /* 0x0024 */ bl .L77000003
> /* 0x0028 */ nop
> .L77000006:
> /* 0x002c 8 */ ret ! Result =
> /* 0x0030 */ restore %g0,%g0,%g0
>
> Note that the result of the strlen() call is put into a
> register. In this case at least, there is no cost to using
> a temporary variable.

I agree that optimization can get rid of NONPSYCHOLOGICAL temp taxes
in the small.

But any programmer who wants to be more than a coder prefers, I think,
the just in time values of expressions to series of "statements" that
agonizingly derive a value, and this was part of my preference,
perhaps in the context misplaced, for a just-in-time evaluation of
strlen.

There is that type of programmer, I claim, who as a worshiper of
Moloch-the-machine is physically offended, repelled, by the idea that
the machine should do any excess work and instead prefers to abase
himself in front of Moloch doing the work himself, thereby
establishing the trust of Moloch as a priest of Moloch lest he himself
be cast into the flames.

Sorry: that was over the top. Let me try again.

There is that type of programmer who likes machines but doesn't like
people. He tends to want to reduce wear and tear on the machine.

John von Neumann was this type of programmer, for when he found that
programmers of ENIAC and IAS were sitting around speculating on
whether they could use the machine to make their jobs easier, Johnny
blew his stack, saying that such expensive and delicate equipment
should not be so used, and that the lads should content themselves
with flipping switches as directed by the mathematicians so we could
finish the job of building the Bomb and blow us all to Kingdom Come.

Grace Hopper on the other hand was amused by the idea and thought it
rather gay that she and the lassies could write primitive high-level
languages. Their early efforts wasted in fact massive anounts of
Johnny's precious computer time because pre-Fortran, high level
languages ran as slow interpreters.

That's perhaps because gals more naturally care about people. Or
something, for here is where angels fear to tread.

A mentor of mine who worked in the 1950s for IBM on the 7044 describes
how he and his coworkers naturally, at any time they needed to, wrote
supporting code in the form of actual assemblers and compilers despite
the fact that his group's mission was to deliver enterprise management
software to American railroads in the form, for example, of a program
that matched freight car heights with tunnel heights.

His gesture "wasted" time and today would not be possible but he and
his coworkers made the railroads happy which made IBM happy.

What's interesting is that the von Neumann psychology persists in this
newsgroup in the form of choruses of dismay at the use of strlen in a
form.

What's REALLY interesting is that absent Hopper's mad, gay adventures
with high level languages THERE WOULD BE NO COMPUTER INDUSTRY.

Instead, we'd all probably be standing in front of one or two World
Computers flipping switches!

I conclude that real programmers love to waste the computer's time
because they know that the wear and tear is a metaphor.



Relevant Pages

  • Re: Testing if a pointer is valid
    ... even though the compiler isn't required to diagnose it. ... Some languages do a better job than others of ... and a programmer only does this if he doesn't know what he is doing. ... int* test ...
    (comp.lang.c)
  • Re: Integer types in embedded systems
    ... First, omitting the "int", even if legal, is sloppy and would not ... I compiler doesn't have to do ... You seem to be a beginning embedded programmer, ... Firstly, yes I'm new to embedded systems, but I consider myself to be ...
    (comp.lang.c)
  • Re: Integer types in embedded systems
    ... Oh, my, I had no idea that you were the ultimate programmer, better ... regardless of options used when invoking the compiler. ... So what size should int be? ... of int instead of char. ...
    (comp.lang.c)
  • Re: error LNK2001: unresolved external symbol
    ... Intellisense will tell you the type of the declaration! ... and the compiler would detect the error anyway. ... was invented, an HWND was a typedef int, a HANDLE was a typedef int, and so on, so the ... checking was made by the programmer who had to check variable prefixes, ...
    (microsoft.public.vc.mfc)
  • Re: any error in the code
    ... Error("Could not allocate the memory\n"); ... or with any other compiler for C. Compare it to the following: ... int if you don't have a C99 ... With a C99 compiler your ...
    (comp.lang.c)