[comp.misc] Program Errors and developement environment

schow@bnr-public.uucp (Stanley Chow) (03/01/89)

In article <881@sceard.UUCP> mrm@sceard.UUCP (M.R.Murphy) writes:
  [Mike Murphy tells us about a list of programming errors that he has 
   kept over the last ten years and asks for additions.    SC]
>
>  1) Is the argument count correct?
>  2) Is the spelling correct?
>  3) Is the argment type correct?
>  4) Is the variable initialized correctly?
>  5) Do "ends" match "do"s?
>  6) Is the correct register used?
>  7) Is a previous equate, using, or define in effect?
>  8) Is the level of indirectness correct?
>  9) Are the defaults correct?
> 10) Is the array large enough to hold the data?
> 11) Is the index out of range?
> 12) Is reentrancy, reusability, refreshability preserved?
> 13) Did you let something go by that you can't explain? Fix it now.
> 14) Does the program have anything remotely to do with the requirement
>     for the program?
> 15) Did you start to code before thinking?
> 16) Did you read the manual?
>
>---
>Mike Murphy  Sceard Systems, Inc.  544 South Pacific St. San Marcos, CA  92069
>mrm@sceard.UUCP       {hp-sdd,nosc,ucsd}!sceard!mrm            +1 619 471 0655


I like to ask people a different question (i.e., cross posting to 
comp.lang.misc) based on this (possiblely expanded list).

   How many of these error can be (are) prevented/encouraged by the
   language (implementation and specification), O/S, developement 
   environment that you use?

   How much cost saving (time & money) could be achived if an environment
   prevents all of these problems? What problems would remain?

Since the religous war potential of this is very high, I suggest everyone
refrain from commenting on C or Ada. Comments on why certain class of errors
is a neccesary evil in a particular language/application should be accompanied
by justification instead of rhetoric.

Please, if you felt "real programmers don't make mistakes", feel free to
start a religous war of your own; don't hide it under my Subject line.


Stanley Chow    ..!utgpu!bnr-vpa!bnr-fos!schow%bnr-public
		(613) 763-2831


P.S. I would volunteer to collect comment and summerize but our mailer is
     quirky and unreliable (as least for me) so I better not.


Since I havn't said anything, and I havn't been paid for saying anything
anyway, I don't think anyone will claim to be represented by any of this.

sommar@enea.se (Erland Sommarskog) (03/03/89)

Stanley Chow (schow@bnr-public.UUCP) writes:
>   How many of these error can be (are) prevented/encouraged by the
>   language (implementation and specification), O/S, developement 
>   environment that you use?
>
>   How much cost saving (time & money) could be achived if an environment
>   prevents all of these problems? What problems would remain?

>M.R.Murphy (mrm@sceard.UUCP) writes:
>>  1) Is the argument count correct?

Can occur with languages with a weak module concept like C and Fortran. 
But are also likely to occur with routines with variable parameter lists 
like for instance VMS system calls.
Gain: Variable parameter lists gives flexibility.
Loss: Harder to detect mistakes. More likely that error causes a crash in
      a live system.

>>  2) Is the spelling correct?

Occurs with totally interpreted languages like DCL or MUMPS.
Gain: Enormous strength for referencing by string manipulation.
Loss: Unbearable for somewhat big programs. I've just condluded
      300 lines of DCL what would have been longer in a compiled
      langauges. But to test it takes longer time.
      
>>  3) Is the argment type correct?

Occurs with untyped or weakly typed langauges like C, Pascal and Lisp(?).  
Gain: Higher flexibility when you really have multi-type arguments.
      (Not with Pascal.) In many applications no gain at all.
Loss: Errors are detected later and will be more expensive.

>>  4) Is the variable initialized correctly?

Occurs with most langauges. Some langauges (e.g. Eiffel, Simula)
defines intial values which saves when the correct initial values
is the same as the one of the langauges. Also, it gives the erroneous
program as a less random appearance. (Works sometimes, sometimes
not.) 
  Although assert statements and similar can help, this is mainly
a programmer issue.

>>  5) Do "ends" match "do"s?

Occurs only in interactive langauges. Simple but fatal errors you 
don't want be afraid to have in your 200000-line system. 

>>  6) Is the correct register used?

Seems like an assembler-only problem.

>>  7) Is a previous equate, using, or define in effect?

Given as C problem, but similar can occur in any block-oriented
language with a WITH or USE statment. Often convenient for short
notation. Problem when over-used.

>>  8) Is the level of indirectness correct?

Sounds like something that would happen with assembler or maybe C.
And, yeah, DCL too. But the levels should never be that many
one one step. More like a programmer issue.

>> 11) Is the index out of range?

Any langauge that allows you to turn off index checks, which means
all. Gain is better performance Loss is strange-behaving programs.

>> 12) Is reentrancy, reusability, refreshability preserved?

Reusabililty at least requires flexibility and modularity. Pascal
is a real loser here. Ada and Eiffel and winners. 

>> 13) Did you let something go by that you can't explain? Fix it now.
>> 14) Does the program have anything remotely to do with the requirement
>>     for the program?
>> 15) Did you start to code before thinking?
>> 16) Did you read the manual?

Programmer issues to most part. Important nevertheless.
-- 
Erland Sommarskog
ENEA Data, Stockholm              This signature is not to be quoted.
sommar@enea.se

holt@turing.toronto.edu (Ric Holt) (03/04/89)

I think the following long question deserves to be clarified, as it
mixes up several concepts that we as Computer Scientists should understand:

*In article <313@bnr-fos.UUCP> schow@bnr-public.UUCP (Stanley Chow) writes:
*>In article <881@sceard.UUCP> mrm@sceard.UUCP (M.R.Murphy) writes:
*>  [Mike Murphy tells us about a list of programming errors that he has 
*>   kept over the last ten years and asks for additions.    SC]
*>>
*>>  1) Is the argument count correct?
*>>  2) Is the spelling correct?
*>>  3) Is the argment type correct?
*>>  4) Is the variable initialized correctly?
*>>  5) Do "ends" match "do"s?
*>>  6) Is the correct register used?
*>>  7) Is a previous equate, using, or define in effect?
*>>  8) Is the level of indirectness correct?
*>>  9) Are the defaults correct?
*>> 10) Is the array large enough to hold the data?
*>> 11) Is the index out of range?
*>> 12) Is reentrancy, reusability, refreshability preserved?
*>> 13) Did you let something go by that you can't explain? Fix it now.
*>> 14) Does the program have anything remotely to do with the requirement
*>>     for the program?
*>> 15) Did you start to code before thinking?
*>> 16) Did you read the manual?

SYNTAX, SEMANTICS AND FAITHFUL EXECUTION

Before going further, we should ask:  What characterizes a language?
We have to understand that a language defines a
SYNTAX (what strings are considered to be programs) and a SEMANTICS
(what do programs mean or do).  A great deal of confusion arises from
the fact that one of the most popular languages, C, has a muddled semantics
(we're not sure what pointers can do and mean; we're not sure what
variable numbers of parameters do and mean; etc).  This muddle shouldn't
detract us from the fact that languages such as Turing have exactly
specified semantics (it is mathematically clear what every construct
does, independent of any implementation).  OK, with that behind us,
we can ask: does the implementation really follow the semantics.  Before
you say "of course", ask questions like: what are the semantics of
dangling pointers, overflows, out of range subscripts, etc.  The concept
of FAITHFUL EXECUTION is defined to mean: the implementation is
required to follow the semantics exactly, or else to halt and notify
the user of the failure.   With the default checking enabled, Turing
gives you faithful execution, stopping and giving you an error
message if ever anything occurs that is outside of the language's
explicit semantics.

DIRT AND DANGER

Now let's go on to DIRTY language features, which by definition have
their meaning determined by underlying implementation details, such
as what's in a particular register (as opposed to CLEAN features, which
are mathematically defined).  Dirty features can be DANGEROUS, meaning
they can cause remote corruption (eg, emitting assembly language by
user control can cause arbitrary corruption that the language 
implementation has have almost no control over).  The Turing Plus
language introduces dirty features, in a controlled fashion, because
these are needed for certain applications.
The problem with dirt and danger is they put a tremendous responsibility
on the programer, which would otherwise be born by the language
implementation.  My guess is that C's degree of dirt and danger
costs 50% in terms of programmer productivity compared with programming
in a faithful language.

SPECIFICATION, CORRECTNESS, STYLE AND METHODOLOGY

Add to these the concepts of SPECIFICATION (what's a program
supposed to do) and CORRECTION (does the program do it) and STYLE
(can you easily read the program and figure out how the program
does it).  METHODOLOLGY means do
you know how to get from a specification to a correct program.

In languages that are generally like Turing (Ada, Modula, Pascal, maybe
	C, etc)
we have:  SYNTAX - enforced by compiler
	  SEMANTICS - produced by compiler and runtime support
	  FAITHFULNESS - enforced by generated code and runtime support
				(depending on language)
	  STYLE - depends on skill and patience of programmer
	  CORRECTNESS - depends on programmer and methodology used
 Now, the questions are categorized using these concepts:

 1) Is the argument count correct?  SYNTAX
 2) Is the spelling correct?  SYNTAX
 3) Is the argment type correct? SYNTAX
 4) Is the variable initialized correctly?  FAITHFUL, CORRECTNESS
 5) Do "ends" match "do"s? SYNTAX
 6) Is the correct register used? DIRTY
 7) Is a previous equate, using, or define in effect? SEMANTICS (DIRTY?)
 8) Is the level of indirectness correct?  SEMANTICS, FAITHFUL
 9) Are the defaults correct?  SEMANTICS, FAITHFUL, CORRECTNESS
10) Is the array large enough to hold the data?  FAITHFUL, CORRECTNESS
11) Is the index out of range?  FAITHFUL, CORRECTNESS
12) Is reentrancy, reusability, refreshability preserved?  SEMANTICS etc
13) Did you let something go by that you can't explain? Fix it now.
				CORRECTNESS, though language design
				helps tremendously to avoid shoot-in-the-
					foot-features.
14) Does the program have anything remotely to do with the requirement
    for the program?   CORRECTNESS
15) Did you start to code before thinking? METHODOLOGY
16) Did you read the manual?  METHODOLGY

The above categorization of questions shows how the corresponding
questions are handled in Turing-like languages.

HOW DOES A LANGUAGE HELP?

A language designed for productivity and
reliability maximizes the degree to which problems are eliminated or
detected by the computer, as opposed to by raw programmer acumen.

As the language becomes less faithful and "dirtier" (Turing
to Pascal to Turing Plus to C to assembler) you sacrifice productivity
and reliability (as a rule).  Similarly, as the language becomes
more interpretive and dynamic in nature (Turing to Basic to APL to
LISP) you get less syntactic help from the computer, as restrictions
designed to help you are put off to run time or eliminated altogether.

		Ric Holt

elliott@hound.UUCP (E.GORELICK) (03/05/89)

This has happened more than once and the program will often compile
and run especially if it is an error trapping routine.

17) Did you comment out part of your code?

You feel really stupid when you find the error.

elliott

hollombe@ttidca.TTI.COM (The Polymath) (03/07/89)

In article <2950@hound.UUCP> elliott@hound.UUCP (E.GORELICK) writes:
}This has happened more than once and the program will often compile
}and run especially if it is an error trapping routine.
}
}17) Did you comment out part of your code?
}
}You feel really stupid when you find the error.

This is the reason I delimit all comments line by line and have fought
to get that practice included in several coding standards.

C example:

     /* This comment is */
     /* delimited line  */
     /* by line.        */

     /*
	  This is the way
	  too many other
	  people do it.
     */

The above example is a trivial oversimplification that doesn't show how
the second form can cause problems.  I've seen several pages of comments,
including some that looked remarkably like source code, delimited with a
single set of /* */.

Also, when deliberately commenting out source code, if you do it line by
line, it makes it much easier to find when scanning through the code and
makes it less easy to forget or not notice that it's been commented out.
(A better technique for this is to use #ifdef BLAH #endif, where BLAH is
not defined. #ifdef BLAH is harder to miss than /*).

I've never accidentally commented out source code since following this
practice. (I've never done it anyway, but better safe than sorry).

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

bill@twwells.uucp (T. William Wells) (03/09/89)

In article <3998@ttidca.TTI.COM> hollombe@ttidcb.tti.com (The Polymath) writes:
: This is the reason I delimit all comments line by line and have fought
: to get that practice included in several coding standards.
:
: C example:
:
:      /* This comment is */
:      /* delimited line  */
:      /* by line.        */
:
:      /*
:         This is the way
:         too many other
:         people do it.
:      */
:
: The above example is a trivial oversimplification that doesn't show how
: the second form can cause problems.  I've seen several pages of comments,
: including some that looked remarkably like source code, delimited with a
: single set of /* */.

There's a much better way of dealing with this: have a lint complain
when a /* occurs in a comment or a /* is not terminated.  Such a
program is very short, less than a hundred lines (write it as a FSM),
and will catch all errors of this type.  Add it to your toolkit and
stop worrying about this problem. No, I don't have such a program
handy; I typically don't make this particular mistake and so I have no
need for one. (I have my own favorite mistakes. :-)

(I know of two compilers that actually do this check and deliver a
warning when a comment is found within a comment.)

The line-by-line style is more difficult to read (one must mentally
subtract the /* */ on each line), more difficult to maintain (one
must remove the /* */ before reformatting text [don't say anything
about emacs, please; all the world's not emacs]), and more difficult
to write (one has to put the pesky things in, often after one has
finished writing the comment).  Not only that, it doesn't really
solve the problem; only discipline will solve that problem, absent an
appopriate tool.  Why use this comment style when there is a simple
tool that eliminates the problem in better ones?

One final note: this is my opinion, I offer my solution to the
problem solely as information with which to aid in choosing a comment
style. I *will not* debate this. I suggest that you don't debate it
either; such debates are rarely fruitful. Just make up your own mind,
pick a consistent style, and adhere to it.

---
Bill
{ uunet | novavax } !twwells!bill
(BTW, I'm going to be looking for a new job sometime in the next
few months.  If you know of a good one, do send me e-mail.)

nick@lfcs.ed.ac.uk (Nick Rothwell) (03/09/89)

My favourite of the "Oh, look, it's commented out" problems is the following
one I ran into in a 1st year's PASCAL program many years ago; it had to print
out a pattern of stars, or somesuch:

PROGRAM ....
   ...
   FOR i := 1 TO 50 DO Write(*);
   ...
   ...lots more code...
   ...
   FOR i := 1 TO 50 DO Write(*);
   ...
END.

The program was perfectly legal; the student couldn't understand why on earth
large chunks of his program were being mysteriously ignored.

		Nick.
--
Nick Rothwell,	Laboratory for Foundations of Computer Science, Edinburgh.
		nick@lfcs.ed.ac.uk    <Atlantic Ocean>!mcvax!ukc!lfcs!nick
~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~ ~~
...while the builders of the cages sleep with bullets, bars and stone,
they do not see your road to freedom that you build with flesh and bone.

   

pattis@june.cs.washington.edu (Richard Pattis) (03/11/89)

X:= 0;		(* Initialize both
Y:= 0;		   X and Y to 0. *)

hollombe@ttidca.TTI.COM (The Polymath) (03/11/89)

In article <756@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes:
}There's a much better way of dealing with this: have a lint complain
}when a /* occurs in a comment or a /* is not terminated.  Such a
}program is very short, less than a hundred lines (write it as a FSM),
}and will catch all errors of this type.  Add it to your toolkit and
}stop worrying about this problem. ...

}... I *will not* debate this. I suggest that you don't debate it
}either; such debates are rarely fruitful. Just make up your own mind,
}pick a consistent style, and adhere to it.

I don't want to debate either, but several people, including you, seem to
have missed my original point, so I'll try to improve my explanation.

I'm not worried about unterminated comments so much as un-noticed comments.
When you've got something like

[much crufty code]
/*
[much crufty code commented out]
*/
[much more crufty code]

It's very easy to miss the fact that those middle lines aren't live code.
That can cause you to waste time trying to fix them or wondering why code
you've added to them doesn't work.

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

bill@twwells.uucp (T. William Wells) (03/15/89)

In article <4032@ttidca.TTI.COM> hollombe@ttidcb.tti.com (The Polymath) writes:
: I don't want to debate either, but several people, including you, seem to
: have missed my original point, so I'll try to improve my explanation.
:
: I'm not worried about unterminated comments so much as un-noticed comments.
: When you've got something like
:
: [much crufty code]
: /*
: [much crufty code commented out]
: */
: [much more crufty code]
:
: It's very easy to miss the fact that those middle lines aren't live code.
: That can cause you to waste time trying to fix them or wondering why code
: you've added to them doesn't work.

I agree. That is why I'd do the above as:

	[much crufty code]
#ifdef notdef
	[much crufty code commented out]
#endif
	[much more crufty code]

Using defines works, first, even if there are comments in the middle
section, and second, is trivial to spot.

So I stand by my original statement.

---
Bill
{ uunet | novavax } !twwells!bill
(BTW, I'm going to be looking for a new job sometime in the next
few months.  If you know of a good one, do send me e-mail.)

wjc@ho5cad.ATT.COM (Bill Carpenter) (03/15/89)

In article <782@twwells.uucp> bill@twwells.uucp (T. William Wells) writes:
> 
> 	[much crufty code]
> #ifdef notdef
> 	[much crufty code commented out]
> #endif
> 	[much more crufty code]

I also use this method because I think it is safer than /**/.  One
suggestion, though, is to use "#if 0 /* reason */".  When I'm looking
at someone else's code or my own old code, if I see "#ifdef notdef",
I'll spend a little time trying to find out if there's any occasion
when it might be defined.  I hope "#if 0" is obvious enough; it is for
me.
--
--
   Bill Carpenter         att!ho5cad!wjc  or  attmail!bill

hollombe@ttidca.TTI.COM (The Polymath) (03/16/89)

In article <7563@june.cs.washington.edu> pattis@june.cs.washington.edu (Richard Pattis) writes:
}X:= 0;		(* Initialize both
}Y:= 0;		   X and Y to 0. *)

A classic example.  If the above had been written:

X:= 0;         (* Initialize both *)
Y:= 0;         (* X and Y to 0.   *)

The problem would never have arisen.  I stand by my recommendation.

-- 
The Polymath (aka: Jerry Hollombe, hollombe@ttidca.tti.com)  Illegitimati Nil
Citicorp(+)TTI                                                 Carborundum
3100 Ocean Park Blvd.   (213) 452-9191, x2483
Santa Monica, CA  90405 {csun|philabs|psivax}!ttidca!hollombe

bill@twwells.uucp (T. William Wells) (03/25/89)

In article <WJC.89Mar15083903@hoswjc.ho5cad.ATT.COM> wjc!ho5cad.att.com (Bill Carpenter) writes:
: In article <782@twwells.uucp> bill@twwells.uucp (T. William Wells) writes:
: >
: >     [much crufty code]
: > #ifdef notdef
: >     [much crufty code commented out]
: > #endif
: >     [much more crufty code]
:
: I also use this method because I think it is safer than /**/.  One
: suggestion, though, is to use "#if 0 /* reason */".  When I'm looking
: at someone else's code or my own old code, if I see "#ifdef notdef",
: I'll spend a little time trying to find out if there's any occasion
: when it might be defined.  I hope "#if 0" is obvious enough; it is for
: me.

When I use '#ifdef notdef' I always remove it before the code leaves
my hands.  I use `notdef' on #ifs so that I can easily find them
before release.

If I do need to keep #ifdefed code in the release, it gets a
meaningful name on the #ifdef.

---
Bill
{ uunet | novavax } !twwells!bill
(BTW, I'm going to be looking for a new job sometime in the next
few months.  If you know of a good one, do send me e-mail.)

zifrony@TAURUS.BITNET (03/28/89)

Maybe the answer is the languages having "till the end of the line" comments,
such as Ada, PostScript, most Assembly languages, FORTRAN, etc.
This way, the programmer cannot delete code by mistake.

The loss of flexibility in the places comments could come seems to me
minor to the gain in security.  Most of the comments I ran to during my
professional programming life were either a comment block (which this comment
style suits just fine), or comments at the end of the line, which can be
acheived using this commenting style as well.

This commenting style can be immitated by the structured-comments languages
such as Pascal and C:

Use a special line to start a comment block, precede each line with '*', and
end it with a special line too.  e.g.:

/*
 *   blah blah blah
 *
*/

End of the line comments should never be written to span over line
boundaries.  use another comment separator-pair if it is too long.

Keep this up, and your commenting problems will disappear.

Doron  Zifrony   zifrony%taurus.bitnet@cunyvm.cuny.edu   or
Msc.   student   zifrony@Math.Tau.Ac.IL
Tel Aviv Univ.
Israel

bill@twwells.uucp (T. William Wells) (03/30/89)

In article <1001@taurus.BITNET> <zifrony%TAURUS.BITNET@CUNYVM.CUNY.EDU> writes:
:
: Maybe the answer is the languages having "till the end of the line" comments,
: such as Ada, PostScript, most Assembly languages, FORTRAN, etc.

Maybe the answer is to just use due care and common sense.

It works for me and my commenting style is

	/* text ...
	   text
	   text */

: This way, the programmer cannot delete code by mistake.

I doubt there is language feature in any language that won't cause
difficulty in interpreting results when misused. The solution?  It
certainly isn't to avoid all language features. Rather, learn coding
styles that minimize difficult to diagnose problems.

With my C comment style, I have to do these things: 1) check for
embedded comments (via my normal linting); 2) if code must be
commented out, use the preprocessor, and not comments; and, if code
is commented out via the preprocessor, use a tag on the #ifdef (like
notdef) that can be searched for so that such can be eliminated.

The result? I don't lose code to comments. And I don't have the
maintenance headaches that mandatory one line comments cause.

---
Bill                            { uunet | novavax } !twwells!bill
(BTW, I'm may be looking for a new job sometime in the next few
months.  If you know of a good one where I can be based in South
Florida do send me e-mail.)