Author: chip Date: Tue Nov 14 09:40:26 2006 New Revision: 15527 Modified: trunk/docs/pdds/pdd07_codingstd.pod
Changes in other areas also in this revision: Modified: trunk/ (props changed) Log: Incremental improvement to pdd07 "coding standards": * Prefer "char *p" to "char* p". * Prefer that structures have both tags and typedefs. * Add "Portability" and "Defensive programming" sections. Modified: trunk/docs/pdds/pdd07_codingstd.pod ============================================================================== --- trunk/docs/pdds/pdd07_codingstd.pod (original) +++ trunk/docs/pdds/pdd07_codingstd.pod Tue Nov 14 09:40:26 2006 @@ -145,6 +145,11 @@ =item * +Pointer types should be written with separation between the star and the base +type, e.g. C<Interp *foo>, but not e.g. <Interp* foo>. + +=item * + There should be one space between C keywords and following open parentheses, e.g. C<return (x+y)*2>. @@ -232,9 +237,13 @@ =item * -All functions must have prototypes in scope at the point of use. Prototypes -for extern functions must appear only in header files. If static functions -are defined before use, their definitions serve as prototypes. +Structure types must have tags. + +=item * + +Functions must have prototypes in scope at the point of use. Prototypes for +extern functions must appear only in header files. If static functions are +defined before use, their definitions serve as prototypes. =item * @@ -255,6 +264,14 @@ =item * +Structure types should have typedefs with the same name as their tags, e.g.: + + typedef struct Foo { + ... + } Foo; + +=item * + Avoid double negatives, e.g. C<#ifndef NO_FEATURE_FOO>. =item * @@ -262,7 +279,7 @@ Do not compare directly against NULL, 0, or FALSE. Instead, write a boolean test, e.g. C<if (!foo) ...>. -(Note: C<PMC*> values should be checked for nullity with the C<PMC_IS_NULL> +(Note: C<PMC *> values should be checked for nullity with the C<PMC_IS_NULL> macro, unfortunately leading to violations of the double-negative rule.) =item * @@ -313,6 +330,110 @@ list of typedefs, and parrot.el should read it or contain it. }} +=head2 Portability + +Parrot runs on many, many platforms, and will no doubt be ported to ever more +bizarre and obscure ones over time. You should never assume an operating +system, processor architecture, endian-ness, size of standard type, or +anything else that varies from system to system. + +Since most of Parrot's development uses GNU C, you might accidentally depend +on a GNU feature without noticing. To avoid this, know what features of gcc +are GNU extensions, and use them only when they're protected by #ifdefs. + + +=head2 Defensive Programming + +=head3 Use Parrot data structures instead of C strings and arrays + +C arrays, including strings, are very sharp tools without safety guards, and +Parrot is a large program maintained by many people. Therefore: + +Don't use a C<char *> when a Parrot STRING would suffice. Don't use a C array +when a Parrot array PMC would suffice. If do use a C<char *> or C array, +check and recheck your code for even the slightest possibility of buffer +overflow or memory leak. + +Note that efficiency of some low-level operations may be a reason to break +this rule. Be prepared to justify your choices to a jury of your peers. + +=head3 Pass only C<unsigned char> to C<isxxx()> and C<toxxx()> + +Pass only values in the range of C<unsigend char> (and the special value -1, +a.k.a. C<EOF>) to the isxxx() and toxxx() library functions. Passing signed +characters to these functions is a very common error and leads to incorrect +behavior at best and crashes at worst. And under most of the compilers Parrot +targets, C<char> I<is> signed. + +=head3 The C<const> keyword on arguments + +Use the C<const> keyword as often as possible on pointers. It lets +the compiler know when you intend to modify the contents of something. +For example, take this definition: + + int strlen(const char *p); + +The C<const> qualifier tells the compiler that the argument will not be +modified. The compiler can then tell you that this is an uninitialized +variable: + + char *p; + int n = strlen(p); + +Without the C<const>, the compiler has to assume that C<strlen()> is +actually initializing the contents of C<p>. + +=head3 The C<const> keyword on variables + +If you're declaring a temporary pointer, declare it C<const>, with the +const to the right of the C<*>, to indicate that the pointer should not +be modified. + + Wango * const w = get_current_wango(); + w->min = 0; + w->max = 14; + w->name = "Ted"; + +This prevents you from modifying C<w> inadvertantly. + + new_wango = w++; /* Error */ + +If you're not going to modify the target of the pointer, put a C<const> +to the left of the type, as in: + + const Wango * const w = get_current_wango(); + if (n < wango->min || n > wango->max) { + /* do something */ + } + +=head3 Localizing variables + +Declare variables in the innermost scope possible. + + if (foo) { + int i; + for (i = 0; i < n; i++) + do_something(i); + } + +Don't reuse unrelated variables. Localize as much as possible, even if +the variables happen to have the same names. + + if (foo) { + int i; + for (i = 0; i < n; i++) + do_something(i); + } + else { + int i; + for (i = 14; i > 0; i--) + do_something_else(i * i); + } + +You could hoist the C<int i;> outside the test, but then you'd have an +C<i> that's visible after it's used, which is confusing at best. + + =head2 CHIP HAS EDITED THIS FAR INTO THE FILE @@ -728,104 +849,11 @@ FOO_valid_value_SETALL(foo); Similarly, avoid using a char* (or {char*,length}) if it is feasible to later -use a PMC* at the same point: cf UTF-8 hash keys in Perl 5. +use a C<PMC *> at the same point: cf UTF-8 hash keys in Perl 5. Of course, private code hidden behind an API can play more fast and loose than code which gets exposed. - -=head2 Portability - -Related to extensibility is portability. Perl runs on many, many platforms, and -will no doubt be ported to ever more bizarre and obscure ones over time. You -should never assume an operating system, processor architecture, endian-ness, -word size, or whatever. In particular, don't fall into any of the following -common traps: - -Internal data types and their utility functions (especially for strings) should -be used over a bare char * whenever possible. Ideally there should be no char * -in the source anywhere, and no use of C's standard string library. - -Don't assume GNU C, and don't use any GNU extensions unless protected by -#ifdefs for non-GNU-C builds. - - -TBC ... Any contributions welcome !!! - - -=head2 Defensive programming - -=head3 The C<const> keyword on arguments - -Use the C<const> keyword as often as possible on pointers. It lets -the compiler know when you intend to modify the contents of something. -For example, take this definition: - - int strlen( const char *p ); - -The C<const> qualifier tells the compiler that the argument will not be -modified. The compiler can then tell you that this is an uninitialized -variable: - - char *p; - int n = strlen(p); - -Without the C<const>, the compiler has to assume that C<strlen()> is -actually initializing the contents of C<p>. - -=head3 The C<const> keyword on variables - -If you're declaring a temporary pointer, declare it C<const>, with the -const to the right of the C<*>, to indicate that the pointer should not -be modified. - - Wango * const w = get_current_wango(); - w->min = 0; - w->max = 14; - w->name = "Ted"; - -This prevents you from modifying C<w> inadvertantly. - - new_wango = w++; /* Error */ - -If you're not going to modify the target of the pointer, put a C<const> -to the left of the type, as in: - - const Wango * const w = get_current_wango(); - if ( n < wango->min || n > wango->max ) { - /* do something */ - } - -=head3 Localizing variables - -Declare variables in the innermost scope possible. - - if ( foo ) { - int i; - for ( i=0; i<n; i++ ) { - do_something(i); - } - } - -Don't reuse unrelated variables. Localize as much as possible, even if -the variables happen to have the same names. - - if ( foo ) { - int i; - for ( i=0; i<n; i++ ) { - do_something(i); - } - } - else { - int i; - for ( i=14; i>0; i-- ) { - do_something_else(i*i); - } - } - -You could hoist the C<int i;> outside the test, but now you'll have an -C<i> that's visible after it's used, which is confusing at best. - =head2 Performance We want Perl to be fast. Very fast. But we also want it to be portable and