2009-07-22 Jb Evain <jbevain@novell.com>
[mcs.git] / CodingStyle
blobaa78389f7b7d05d136764df67ef9e87fbc554fc5
1 * Coding Style for the Mono C# source code.
3 * Class Libraries and Assembly Layout
5         The class libraries are grouped together in the assemblies
6         they belong.
7         
8         Each directory here represents an assembly, and inside each
9         directory we divide the code based on the namespace they
10         implement.
11         
12         In addition, each assembly directory contains a Test directory
13         that holds the NUnit tests for that assembly.
14         
15         We use a new build system which is described by various README
16         files in mcs/build
17         
18         The build process typically builds an assembly, but in some
19         cases it also builds special versions of the assemblies
20         intended to be used for testing.
22 * Missing implementation bits
24         If you implement a class and you are missing implementation bits,
25         please use the attribute [MonoTODO].  This attribute can be used
26         to programatically generate our status web pages:
28         [MonoTODO("My Function is not available on Mono")]
29         int MyFunction ()
30         {
31                 throw new NotImplementedException ();
32         }
34         Ideally, write a human description of the reason why there is
35         a MonoTODO, this will be useful in the future for our
36         automated tools that can assist in developers porting their code.
38 * Supporting .NET 1.2, .NET 1.1 and .NET 1.0 builds
40         The defines NET_1_1 and NET_2_0 are used to include
41         features.   When NET_2_0 is defined, it also implies that the
42         NET_1_1 is defined.
44         To have code which is only available in an old version, use ONLY_1_0,
45         ONLY_1_1
47 * Tagging buggy code
49         If there is a bug in your implementation tag the problem by using
50         the word "FIXME" in the code, together with a description of the 
51         problem.
53         Do not use XXX or obscure descriptions, because otherwise people
54         will not be able to understand what you mean.
56 * Tagging Problematic specs.
58         If the documentation and the Microsoft implementation do
59         differ (you wrote a test case to prove this), I suggest that you edit
60         the file `mcs/class/doc/API-notes' so we can keep track of these problems
61         and submit our comments to ECMA or Microsoft and seek clarification.
63         Sometimes the documentation might be buggy, and sometimes the implementation
64         might be buggy.  Lets try to identify and pinpoint which one
65         is the correct one.
67         Sometimes the specification will be lame (consider Version.ToString (fieldCount)
68         where there is no way of knowing how many fields are available, making the API
69         not only stupid, but leading to unreliable code).
71         In those cases, use the keyword "LAMESPEC".
72         
74 * Coding considerations and style.
76         In order to keep the code consistent, please use the following
77         conventions.  From here on `good' and `bad' are used to attribute
78         things that would make the coding style match, or not match.  It is not
79         a judgement call on your coding abilities, but more of a style and 
80         look call.  Please try to follow these guidelines to ensure prettiness.
82         Use 8 space tabs for writing your code (hopefully we can keep
83         this consistent).  If you are modifying someone else's code, try
84         to keep the coding style similar.
86         Since we are using 8-space tabs, you might want to consider the Linus
87         Torvals trick to reduce code nesting.  Many times in a loop, you will
88         find yourself doing a test, and if the test is true, you will nest.
89         Many times this can be changed.  Example:
92                 for (i = 0; i < 10; i++) {
93                         if (something (i)) {
94                                 do_more ();
95                         }
96                 }
98         This take precious space, instead write it like this:
100                 for (i = 0; i < 10; i++) {
101                         if (!something (i))
102                                 continue;
103                         do_more ();
104                 }
106 * Performance and readability
108         It is more important to be correct than to be fast.
110         It is more important to be maintainable than to be fast.
112         Fast code that is difficult to maintain is likely going to
113         be looked down upon.
115 * Style Guidelines
117                 * Use a space before an opening parenthesis when calling
118                   functions, or indexing, like this:
120                         method (a);
121                         b [10];
123                 * Do not put a space after the opening parenthesis and the 
124                   closing one, ie:
126                         good: method (a);       array [10];
128                         bad:  method ( a );     array[ 10 ];
130                 * Inside a code block, put the opening brace on the same line
131                   as the statement:
133                         good:
134                                 if (a) {
135                                         code ();
136                                         code ();
137                                 }
139                         bad:
140                                 if (a) 
141                                 {
142                                         code ();
143                                         code ();
144                                 }
146                 * Avoid using unecessary open/close braces, vertical space
147                   is usually limited:
149                         good:
150                                 if (a)
151                                         code ();
153                         bad:
154                                 if (a) {
155                                         code ();
156                                 }
158                 * When defining a method, use the C style for brace placement, 
159                   that means, use a new line for the brace, like this:
161                         good:
162                                 void Method ()
163                                 {
164                                 }
166                         bad:
167                                 void Method () {
168                                 }
170                 * Properties and indexers are an exception, keep the
171                   brace on the same line as the property declaration.
172                   Rationale: this makes it visually
173                   simple to distinguish them.
175                         good:
176                                 int Property {
177                                         get {
178                                                 return value;
179                                         }
180                                 }
182                         bad:
183                                 int Property 
184                                 {
185                                         get {
186                                                 return value;
187                                         }
188                                 }
190                   Notice how the accessor "get" also keeps its brace on the same
191                   line.
193                   For very small properties, you can compress things:
195                         ok:
196                                 int Property {
197                                         get { return value; }
198                                         set { x = value; }
199                                 }
201                 * Use white space in expressions liberally, except in the presence
202                   of parenthesis:
204                         good:
206                                 if (a + 5 > method (blah () + 4))
208                         bad:
209                                 if (a+5>method(blah()+4))
211                 * For any new files, please use a descriptive introduction, like
212                   this:
214                         //
215                         // System.Comment.cs: Handles comments in System files.
216                         //
217                         // Author:
218                         //   Juan Perez (juan@address.com)
219                         //
220                         // (C) 2002 Address, Inc (http://www.address.com)
221                         //
223                 * If you are modyfing someone else's code, and your contribution
224                   is significant, please add yourself to the Authors list.
226                 * Switch statements have the case at the same indentation as the
227                   switch:
229                         switch (x) {
230                         case 'a':
231                                 ...
232                         case 'b':
233                                 ...
234                         }
236                 * Argument names should use the camel casing for
237                   identifiers, like this:
239                         good:
240                                 void Method (string myArgument)
242                         bad:
243                                 void Method (string lpstrArgument)
244                                 void Method (string my_string)
246                 * Empty methods: They should have the body of code using two    
247                   lines, in consistency with the rest:
249                         good:
250                                 void EmptyMethod ()
251                                 {
252                                 }
254                         bad:
255                                 void EmptyMethod () {}
257                                 void EmptyMethod () 
258                                 {}
259                 
260                 * Line length: The line length for C# source code is 134 columns.
263                   If your function declaration arguments go beyond
264                   this point, please align your arguments to match the
265                   opening brace, like this:
267                         void Function (int arg, string argb,
268                                        int argc)
269                         {
270                         }
271          
272                   When invoking functions, the rule is different, the
273                   arguments are not aligned with the previous
274                   argument, instead they begin at the tabbed position,
275                   like this:
276           
277                         void M ()
278                         {
279                                 MethodCall ("Very long string that will force",
280                                         "Next argument on the 8-tab pos",
281                                         "Just like this one")
282                 
283                         }
285                 * Variable declaration indentation.
287                   Sometimes it is convenient to indent the variables to make the code
288                   look pretier, but do not add gratuitous space, try to use the minimally
289                   necessary space, for example:
291                   Good:
293                         void Method ()
294                         {
295                                 string b;
296                                 int    a;
297                                 byte   c;
298                         }
300                   Bad:
302                         void Method ()
303                         {
304                                 string          b;
305                                 int             a;
306                                 byte            c;
307                         }
309                 * Braces and the `else' clause
311                   If there are braces closing or opening next to the else clause,
312                   they go on the same line as the word `else', for example:
314                   Good:
316                         if (..) {
318                         } else {
319                 
320                         }
321         
322                   Bad:
324                         if (..) {
326                         } 
327                         else {
328                 
329                         }
331                   Bad:
333                         if (..) {
335                         } else 
336                         {               
337                         }
339                   Bad:
341                         if (..) {
343                         } 
344                         else 
345                         {
346                 
347                         }
349 * RCS and CVS tags
351         Some users like to use the special RCS/CVS tags in their
352         source code: $id$, $log$ and so on.  
354         The use of these is not permitted on the Mono source code
355         repository.   This metadata belongs on a ChangeLog or in the
356         SVN metadata. 
358 * File formats
360         Historically our repository has used a mix of line-endings,
361         this is a mistake that we are trying hard to fix.
363         For existing files, please make sure that you do not convert 
364         the file, as that causes us to loose precious history (the
365         full file is commited).
367         For new files that you create, please make sure that you use
368         Subversion's support for mapping the line endings
369         automatically, after adding your file:
371                 $ svn add file.cs
373         Execute this command:
375                 $ svn propset svn:eol-style native file.cs
377         Which will make the file automatically receive the proper
378         treatment from that point on.
380         Please verify before commiting that your changes wont loose
381         history, you can do this by running:
383                 $ svn diff
385         And examining the output.
387 * ChangeLogs
389         ChangeLogs are the files that we use to track the project
390         history.  ChangeLogs are found one per directory, or in small
391         projects, one per project.
393         The format looks like this:
395         2004-11-19  Raja R Harinath  <rharinath@novell.com>
397                 * Makefile (%-profiles): Go through an intermediate
398                 set of rules.  Move body to ...
399                 (profiles-do--%): ... this.
400                 (profiles-do--run-test): Customized rule that usefully
401                 runs with 'make -j' and 'make -k'.
402                 (profiles-do--all, profile-do--%--all): Orchestrate
403                 the bootstrap process.
405                 * file.cs (MainForm): Updated version.
407         The date, author, email address in the first line.
409         From that point on a list of changes in a file-by-file basis,
410         describing what changes were done.
412         This information must be cut and pasted into your commit
413         message, so the information ends up in two places: in the
414         subversion repository metadata and also on the source code
415         distirbution (which does not have the Subversion metadata).
416                 
417 * Warnings
419         Avoid commiting code with warnings to the repository, the use
420         of #pragmas to disable warnings is strongly discouraged, but
421         can be used on unique cases.  Please justify the use of the
422         warning ignore clause on a comment.
424         Do not commit changes to the Makefiles that removes warnings,
425         if anything warnings should be eliminated one at a time, and
426         if not possible, they must be flagged.
429 * Examples:
431 class X : Y {
433         bool Method (int argument_1, int argument_2)
434         {
435                 if (argument_1 == argument_2)
436                         throw new Exception (Locale.GetText ("They are equal!");
438                 if (argument_1 < argument_2) {
439                         if (argument_1 * 3 > 4)
440                                 return true;
441                         else
442                                 return false;
443                 }
445                 //
446                 // This sample helps keep your sanity while using 8-spaces for tabs
447                 // 
448                 VeryLongIdentifierWhichTakesManyArguments (
449                         Argument1, Argument2, Argument3,
450                         NestedCallHere (
451                                 MoreNested));
452         }
454         bool MyProperty {
455                 get {
456                         return x;
457                 }
459                 set {
460                         x = value;
461                 }
462         }
464         void AnotherMethod () 
465         {
466                 if ((a + 5) != 4) {
467                 }
469                 while (blah) {
470                         if (a)
471                                 continue;
472                         b++;
473                 }
474         }
477 * Conditional compilation
479         Ideally we would not need conditional compilation, and the use
480         of #ifdef is strongly discouraged.  But due to our support for
481         old C# 1.0 compilers we have to use it in a few places.
483         Try to avoid negative tests that have an else clause, for
484         example:
486             #if !NET_2_0
487                 CODE_FOR_1_0
488             #else
489                 CODE_FOR_2_0
490             #endif
492         Instead use:
494             #if NET_2_0
495                 CODE_FOR_2_0
496             #else
497                 CODE_FOR_1_0
498             #endif
500         When a major feature differs across compilation targets, try
501         to factor out the code into a separate class, a helper class
502         or a separate file, and include that in your profile while
503         surrounding that helper file/class with the ifdefs to reduce
504         the amount of ifdefs in the code.
506         For instance, this is used for some parts of Grasshopper where
507         the code is ifdefed out, when large parts of a file would have
508         been ifdefed out, we moved the code into a MyOtherFile.jvm.cs
510         For 2.0 classes, this is even simpler as code can be trivially
511         factored out into 
513                  MyHelperClass.cli.cs
514                  MyHelperClass.jvm.cs
516         By using partial classes.