Writing Bug-Free C/D Code

Knud Soerensen 4tuu4k002 at sneakemail.com
Mon Mar 19 09:18:42 PDT 2007


On Mon, 19 Mar 2007 16:02:04 +0100, Henning Hasemann wrote:

> On Mon, 19 Mar 2007 14:20:31 +0000 (UTC)
> Knud Soerensen <4tuu4k002 at sneakemail.com> wrote:
> 
>> Well, I think your problems is due to fundamental errors in your
>> programming method. :-)
>> 
>> We all know the ordinary form of Hungarian notation as described in
>> http://www.duckware.com/bugfreec/chapter3.html#naming
>> but there is also a stronger form called app-Hungarian notation
>> where the prefix gives a hint of the purpose for the variable.
>> Like rowPos for a row position and colPos for a column position.
>> Now it is easy to spot buggy code like rowPos=colPos etc.
> 
> I always name my variables like this. Personally I event tend to
> not use such shortcut-names as they sometimes tend do be misleading
> and hard to read. (row is clear, but later you might come to a point
> where you or someone in your project uses column because he thinks its
> short enough and so on).
> Also this has nothing to do with my problems, because my problem is
> not that I adding things together that have nothing to do with
> each other, but adding things together that *have* to do with
> each other but are often of different signedness.

well in your talk about adding a unsigned position with a signed width 
to get a new position.

Idealy I would do
typedef int WIDTH;
typedef int POSITION;
POSITION.invariant {
 assert(0 <= value);
}

void main()
{
	POSITION pos=10;
	WIDTH wid=-2;
	pos=cast(POSITION)(pos+wid);
}

First it encapsulates the problem in the typedef,
the cast help to make it clear what is happening  
and invariant allow us to test for runtime errors. 

>> Using a type system we can take the idea a step further.
>> 
>> typedef int ROWPOS;
>> typedef int COLPOS;
>> 
>> foo 
>> {
>>   ROWPOS rowPos;
>>   COLPOS colPos;
>>  
>>   rowPos = colPos; // error at compiler time.
>> }
> 
> Yeah sometimes I tend to this too,
> but not for preventig errors like rowPos = colPos (as the
> naming you suggested helps me enough). 
> But I also try to be careful
> not to have too much typedefs and/or aliases (yes I know the difference)
> to trivial types such as int as it might confuse a reader
> that assumes something special or magical beyond this.

Well, it can also be used as a help:

typedef float RADIANS;
main 
{
  2dshape box;
  ...
  box.rotate(cast(RADIANS)1.54);
}
Here it makes the code more readable and less confusing.
 

	
>> So, the fundamental flaw is that you use raw types instead
>> of making a type for each purpose in your code.
> 

Remember we are talking about writing complete bug free programs here.
That means that we ideally should be able to catch every conceivable bug
early.

> Are you really sure it is a good idea to have a typedef for each
> purpose? So a point struct would look like this for you:
> 
> typedef int COORD;
> struct Point {
>   COORD x, y;
> }
> 
> right?
No, like.
typedef int XCOORD;
typedef int YCOORD;
struct Point {
 XCOORD x; YCOORD y;
}
 Or else your might get x and y confused :-)

> 
> Dont get me wrong, I dont want to criticize this way of doing things
> its just I never done it so much before because I am not sure
> it is such a good idea.
> 
>> Could the compiler do something about it ?
>> Yes, it could provide a switch called -bugfree 
>> which trows a error every time a non user defined type is
>> used in the code.
> 
> C'mon, that would be silly.

Well the idea with the -bugfree switch was to be able 
to catch every conceivable bug at compiler time, 
not to go easy on the programmer :-)

> 
>> It would also be useful if we could add an invariance to the type
>> instead of have to change it into a class or structure.
> 
> You mean something like
> typedef ubyte DiceResult;
> 
> DiceResult.invariant {
>    assert(1 <= value);
>    assert(value <= 6);
> }
> 

Exactly.

> ... would be handy sometimes, I agree. 
> 
> Henning
>



More information about the Digitalmars-d mailing list