forked from zeromq/rfc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spec_21.txt
1013 lines (666 loc) · 38.5 KB
/
spec_21.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
The C Language Style for Scalability (CLASS) defines a consistent style and organization for scalable C library and application code built on modern C compilers and operating systems. CLASS aims to collect industry best practice into one reusable standard.
* Name: rfc.zeromq.org/spec:21/CLASS
* Editor: Pieter Hintjens <ph@imatix.com>
* State: stable
++ License
Copyright (c) 2009-2013 iMatix Corporation
This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This Specification is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses>.
++ Change Process
This Specification is a free and open standard[((bibcite fandos))] and is governed by the Digital Standards Organization's Consensus-Oriented Specification System (COSS)[((bibcite coss))].
++ Language
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119[((bibcite rfc2119))].
++ Goals
CLASS aims to be a complete and reusable style and organization guide for scalable C projects. CLASS collects best practice to solve a set of specific and well-known quality problems with C projects. It evolved from the style guide of the ZeroMQ [https://github.com/zeromq/czmq CZMQ project]. CLASS is plug compatible with the "coding style guide" requirements of the C4 process[((bibcite c4))].
The specific goals for this Specification are to:
* Give project maintainers and contributors a tool for measuring the quality of patches to a project.
* Give the code the appearance of a single perfect author writing at one moment in time.
* Reduce the number of lines of code and complexity of C projects.
* Ensure total consistency of every line of code, across a large number of projects.
* Reduce the risk of writing C code by solving common C style problems in a minimal fashion.
* Provide a vehicle to collect best practice over time.
+++ Quality Aspirations
The goal of CLASS is to help programmers write high-quality C code in a consistent fashion. We define "high quality" primarily thus:
* The code is easy to read and understand even if you know little or nothing about its specific context.
* The code is easy to reuse and remix, in whole or in fragments.
* The code is easy to write correctly, and errors are rapidly clear.
Our main tool for achieving this is to identify and apply the best patterns and styles. Tthe reader can learn these once, and then see them repeatedly across a wide body of code. Deviations from familiar patterns can then be taken as a sign of low-quality code that is more likely to contain errors and less remixable.
+++ Common Problems
With this Specification we aim to address a specific set of problems that hurt the quality, remixability, and economics of many C projects:
* If there is no style guide for a project, the maintainers must either rewrite contributions by hand (which costs extra work), or must abandon any attempt to enforce a consistent "voice" across a project (which hurts code quality and reusability). Thus maintainers need a written style guide to which they can point contributors.
* If there is no reusable style guide, each project founder will improvise their own ad hoc style. This wastes previous experience, and creates unnecessary work for project founders. It also means each project will end up with a different style.
* If a set of projects each have a different style, they cannot share code easily, which damages the economics of remixing. The more projects that use a single style, the lower the cost of code reuse. This is especially important in open source but also applies to projects built internally in an organization.
* With no vehicle for collecting and sharing best practices in C programming, most projects will have mediocre structuring and style, leading to unnecessary complexity, excess lines of code, accumulation of unused code, and other quality problems.
* When project founders create a new project without help, they often make mistakes such as forgetting to define a license for their code. This can create legal problems.
While these problems can affect all software projects, we solve them specifically for C projects.
++ General Style
+++ Definitions
The overall unit of work is a //project// that builds as a library with a set of executable test programs and supplemental command-line tools.
The project is composed of //classes//, where each class covers one area of work and is implemented as a source file with matching header file.
Each class implements a series of //methods//, where each method performs one task and is implemented as a C function.
+++ Language
The language for all names and comments SHALL be English.
+++ Naming
Names SHOULD be chosen for ease of readability, and consistency. Unless otherwise specified, the following style rules apply to all given names:
* Names SHALL be short words that are simple, clear, and obvious to the reader.
* Names SHALL be used consistently for any given semantics.
* Names SHOULD NOT be invented words or acronyms.
* Names MAY be abbreviations if used widely.
* Names SHALL NOT be reserved C or C++ keywords.
++ Project Style
+++ Project Focus
The project SHALL focus on one identifiable problem space, which SHALL be stated explicitly in the project {{README}}.
+++ Project Name
The project SHALL have these short names and abbreviations:
* A //project short name// used in paths and URLs that identify the project. This would be used for instance in the GitHub project name. In this Specification we will use {{myproject}} as the example.
* A //project abbreviation// used for project files and output libraries. This would be used for instance in the library produced for the project. The abbreviation MAY be an acronym. In this Specification we will use {{myproj}} as the example.
* A //project prefix// used to prefix all method names, which MAY be the same as the project abbreviation. This would be used in source code and its API. The prefix SHOULD end with an underscore. In this Specification we will use {{myp_}} as the example.
These names SHALL be noted in the project {{README}}.
+++ General Layout
The project SHALL contain at least these files and directories:
* A {{README}} file that refers to this Specification and provides other necessary information about the project.
* A license file (e.g., {{COPYING}} or {{LICENSE}}) that specifies the terms of distribution for the project.
* An {{include}} directory for all header files.
* A {{src}} directory for all library source files.
* The //external header file// ({{myproj.h}}).
* Scripts and makefiles to build and test the project on at least one platform.
The project MAY contain these files and directories which MUST have these names if present at all:
* An {{AUTHORS}} file listing all contributors to the project.
* A {{doc}} directory containing documentation.
* A {{tests}} directory containing self-test programs, built with the project.
* A {{tools}} directory containing command-line tools.
* The //internal header file// ({{myproj_internal.h}}).
The project SHOULD install these files:
* The project header files and all class header files that form part of the public API.
* The project library, named with the project abbreviation ({{libmyproj.a}} on POSIX platforms, {{myproj.dll}} on Windows).
* Command-line tools, if present.
The project SHALL NOT use deeper nested subdirectories.
+++ Dependencies
The project SHALL depend at least on CZMQ (libczmq), which imports ZeroMQ (libzmq), to provide portable APIs around networking, threads, file systems, and other aspects.
+++ Project Header Files
The project SHALL provide two services via header files:
# A set of internal definitions to class source files, which a class source file can access with a single {{include}} statement.
# A public API that calling applications can access with a single {{include}} statement.
These two services MAY be combined into one project header file (({{myproj.h}}), or MAY be split into an external header file ({{myproj.h}}) and an internal header file ({{myproj_internal.h}}). The project MAY further break down these header files if necessary.
The external header file SHALL define a version number for the project as follows:
[[code]]
// MYPROJ version macros for compile-time API detection
#define MYPROJ_VERSION_MAJOR 1
#define MYPROJ_VERSION_MINOR 0
#define MYPROJ_VERSION_PATCH 0
#define MYPROJ_MAKE_VERSION(major, minor, patch) \
((major) * 10000 + (minor) * 100 + (patch))
#define MYPROJ_VERSION \
MYPROJ_MAKE_VERSION(MYPROJ_VERSION_MAJOR, \
MYPROJ_VERSION_MINOR, \
MYPROJ_VERSION_PATCH)
[[/code]]
The project header file SHALL assert the required version numbers for any dependencies immediately after including their respective header files, like this:
[[code]]
#include <czmq.h>
#if CZMQ_VERSION < 10203
# error "myproject needs CZMQ/1.2.3 or later"
#endif
[[/code]]
Definitions in the external header file are visible to calling applications as well as class source code. The external header file SHALL include all class header files that form part of the public API for the project.
Definitions in the internal header file are visible only to class source code. The internal header file, if present, SHALL include the external header file, all class header files, and all system and library header files needed by the project. The primary goal here is to keep delicate system-dependent {{#include}} chains in a single place, and away from class source code.
+++ Template README File
[[code]]
# Project Title
<One-paragraph statement of the goals of the project, and the problems it aims to solve>
## References
* Contribution policy is defined by C4 (http://rfc.zeromq.org/spec:21).
* Project style guide is defined by CLASS (http://rfc.zeromq.org/spec:14).
* short name: <shortname>
* abbreviation: <abbreviation>
* prefix: <prefix>
* Licensed under <license name>, see COPYING
* Language level: C99
[[/code]]
+++ Language Level
The project SHOULD use the C99 language for best clarity, but MAY use the C89 language for compatibility with older platforms. The language level SHALL be noted in the project {{README}} and all source code SHALL conform to it.
NOTE: Microsoft Visual C/C++ does //not// support C99 and projects must build using C++ language extensions to get access to C99 syntax. Because of this, projects SHOULD NOT use any C99 syntax that is not a strict subset of C++.
+++ Use of the Preprocessor
Project source code SHALL NOT include any header files except the project header file. This ensures that all class source code compiles in exactly the same environment.
Project source code SHALL NOT define "magic numbers" (numeric constants); these SHALL be defined in the external or internal header file, as appropriate.
Projects MAY use the preprocessor for these purposes:
* To create backwards compatibility with older code.
* To improve portability by e.g., mapping non-portable system calls into more portable ones.
* To create precise, small macros with high usability.
Projects SHOULD NOT use the preprocessor for other work except when it significantly reduces the complexity of code.
Macro names SHALL be uppercase when they represent constants, and lowercase when they act as functions.
++ Class Styles
+++ File Organization
Each class SHALL be written as two files:
* A header file: {{include/myp_mymod.h}}
* A source file: {{src/myp_mymod.c}}
These two files SHALL be the original documentation for the class. Specifically, the class header SHALL define the API for the class, and the class source file SHALL define the implementation of each method.
Class names SHALL follow the General Style for Naming. We will use {{mymod}} in examples.
Every source and header file SHALL start with an appropriate file header that states at least:
* The name of the class or file and its purpose
* The copyright statement for the class
* The name of the project and a URL if relevant
* The summary license statement
Here is a template file header for an LGPL open source project:
[[code]]
/* =========================================================================
<name> - <description>
-------------------------------------------------------------------------
Copyright (c) <year> - <company name> - <website>
Copyright other contributors as noted in the AUTHORS file.
This file is part of <project name>, <description>
<website>
This is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
This software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT-
ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not see http://www.gnu.org/licenses.
=========================================================================
*/
[[/code]]
+++ Class Types
We define two types of class:
* //Stateful classes//, where the class provides methods working on //instances//, which are like "objects" in an object-oriented language.
* //Stateless classes//, where the class provides methods that work purely on data provided by the caller or system.
A class may be stateful or stateless but SHALL NOT mix the two approaches.
A stateful class SHALL provide these methods:
* A constructor method {{myp_mymod_new ()}}
* A destructor method {{myp_mymod_destroy ()}}
* A self-test method {{myp_mymod_test ()}}
A stateful class MAY provide these methods, and SHALL use these names when providing such functionality:
* A duplicator method {{myp_mymod_dup ()}}
* A set of list navigation methods {{myp_mymod_first ()}} and {{myp_mymod_next ()}}.
* Print methods {{myp_mymod_print ()}} and {{myp_mymod_fprint ()}}.
A stateless class SHALL provide this method:
* A self-test method {{myp_mymod_test ()}}
+++ Method Names
Method names SHALL follow the General Style for Naming. Method names SHOULD be verbs ("destroy", "insert", "lookup") or adjectives ("ready", "empty", "new"). The method name SHOULD imply the method return type, where verbs return a success/failure indicator, if anything, and adjectives return a value or instance.
+++ Class Header File
The class header file SHALL have this layout:
* The file header
* An outer {{#ifndef}} that makes it safe to include the header file multiple times
* Calling conventions for C++
* A forward reference to the class type, for stateful classes
* Prototypes for the class methods
Here is a template header file for stateful classes, not showing the file header:
[[code]]
#ifndef __MYMOD_H_INCLUDED__
#define __MYMOD_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
// Opaque class structure
typedef struct _myp_mymod_t myp_mymod_t;
// Create a new <class name> instance
CZMQ_EXPORT myp_mymod_t *
myp_mymod_new (void);
// Destroy a <class name> instance
CZMQ_EXPORT void
myp_mymod_destroy (myp_mymod_t **self_p);
// Self test of this class
void
myp_mymod_test (bool verbose);
#ifdef __cplusplus
}
#endif
#endif
[[/code]]
Here is a similar template header file for stateless classes:
[[code]]
#ifndef __MYMOD_H_INCLUDED__
#define __MYMOD_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
// Self test of this class
int
myp_mymod_test (bool verbose);
#ifdef __cplusplus
}
#endif
#endif
[[/code]]
All public methods SHALL be declared with {{CZMQ_EXPORT}} in the class header file so that these methods are properly exported on operating systems that require it.
+++ Class Source File
The class source file SHALL define:
* The class structure, for stateful classes. This structure SHALL be //opaque// and known only to code in the class source file.
* The class methods, in the same order as defined in the class header: constructor, destructor, other methods, and finally self test.
* Any static functions used in the class methods.
* Any global or static variables needed.
+++ Class Properties
For stateful classes, the class structure has one or more properties defined as a private C structure in the class source file.
This SHOULD be defined as follows:
[[code]]
// Structure of our class
struct _mymod_t {
<type> <name>; // <description>
};
[[/code]]
Property names SHALL follow the General Style for Naming. Property names SHOULD be nouns or adjectives (typically used for Boolean properties). We will use {{myprop}} in examples.
++ Method Styles
+++ General Rules
++++ Argument Names
Argument names SHALL be consistent with property names.
+++ The Self Test Method
In stateless classes, the only standard method is {{myp_mymod_test ()}}, which SHALL conduct a self test of the class, returning silently on success, and asserting on failure.
The self test method shall take this general form:
[[code]]
// --------------------------------------------------------------------------
// Runs selftest of class
void
myp_mymod_test (int verbose)
{
printf (" * myp_mymod: ");
// Conduct tests of every method
printf ("OK\n");
}
[[/code]]
* The self test method SHALL be a primary source of example code for users of the class.
* The self test method SHOULD cover every other method in the class.
+++ Stateful Classes
++++ The Constructor Method
The constructor SHALL take this general form:
[[code]]
// Create a new myp_mymod instance
myp_mymod_t *
myp_mymod_new (<arguments>)
{
myp_mymod_t *self = (myp_mymod_t *) zmalloc (sizeof (myp_mymod_t));
if (self) {
self->someprop = someprop_new ();
if (self->someprop)
self->anotherprop = anotherprop_new ();
if (self->anotherprop)
self->lastprop = lastprop_new ();
else
myp_mymod_destroy (&self);
}
return self;
}
[[/code]]
* The constructor SHALL initialize all properties in new class instances. Properties SHALL either get a suitable initial value, or be set to zero. Very large properties MAY exceptionally be left uninitialized for performance reasons; such behavior MUST be explicitly noted in the constructor body.
* Any properties that are dynamically allocated SHOULD be allocated in the constructor but MAY be left as null.
* The constructor MAY take one or more arguments, which SHALL correspond to properties to be initialized.
* The constructor SHALL return either a new instance reference, or null, if construction failed, in which case all memory allocated during construction SHALL be released.
++++ The Destructor Method
The destructor SHALL take this general form:
[[code]]
// Destroy a myp_mymod instance
void
myp_mymod_destroy (myp_mymod_t **self_p)
{
assert (self_p);
if (*self_p) {
myp_mymod_t *self = *self_p;
someprop_destroy (&self->someprop);
anotherprop_destroy (&self->anotherprop);
lastprop_destroy (&self->lastprop);
free (self);
*self_p = NULL;
}
}
[[/code]]
* The destructor SHALL nullify the provided instance reference.
* The destructor SHALL be idempotent, i.e., can be called safely on the same instance reference more than once.
* The destructor SHALL safely free properties and child class instances that are not null.
++++ The Duplicator Method
The class MAY offer a duplicator method which creates a full copy of an instance; if it offers such semantics, the method MUST be called {{myp_mymod_dup ()}} and take this general form:
[[code]]
// Create a copy of a myp_mymod instance
myp_mymod_t *
myp_mymod_dup (myp_mymod_t *self)
{
if (self) {
assert (self);
myp_mymod_t *copy = myp_mymod_new (...);
if (copy) {
// Initialize copy
}
return copy;
}
else
return NULL;
}
[[/code]]
* The duplicator SHALL return either a new instance reference, or null, if construction failed, in the same manner as the constructor.
* The duplicator SHALL accept a null instance reference, and then return null.
* A duplicated instance SHALL be entirely independent of the original instance (i.e. all properties SHALL also be duplicated).
++++ List Navigation Methods
A class MAY act as a list container for other items, which may be child class instances, strings, memory blocks, or other structures.
Such a container class SHALL keep the list cursor position in the instance, and provide the following methods for navigating the list:
[[code]]
// Return first item in the list or null if the list is empty
item_t *
myp_mymod_first (myp_mymod_t *self)
{
assert (self);
// Reset cursor to first item in list
return item;
}
// Return next item in the list or null if there are no more items
item_t *
myp_mymod_next (myp_mymod_t *self)
{
assert (self);
// Move cursor to next item in list
return item;
}
[[/code]]
* The navigation methods SHALL return null to indicate "no more items".
* The navigation methods SHALL be idempotent, and specifically, calling {{myp_mymod_next ()}} when at the end of the list SHALL return null each time.
* The class MAY offer {{myp_mymod_last ()}} and {{myp_mymod_prev ()}} methods.
* The class MAY offer {{myp_mymod_size ()}} which returns the list size.
* If the class offers methods to create list items, these SHALL be called {{myp_mymod_append ()}} (to add to the end of the list) and {{myp_mymod_insert ()}} (to add to the start of the list).
* If the class offers a method to remove a list item, this SHALL be called {{myp_mymod_delete ()}}; it SHALL take the item reference as argument, and it SHALL delete the first matching item in the list, if any.
* If the class maintains multiple lists, it SHALL create unique method names for each list by adding a list name, e.g., {{myp_momod_myitem_first ()}}.
++++ Accessor Methods
The class MAY expose instance properties via its API, in which case this SHALL be done through accessor methods.
To return the value of a property the class SHALL define an accessor method like this:
[[code]]
// Return the value of myprop
<type>
myp_mymod_myprop (myp_mymod_t *self)
{
assert (self);
return self->myprop;
}
[[/code]]
To write the value of a property, if this is permitted, the class SHALL define an accessor method like this:
[[code]]
// Set the value of myprop
void
myp_mymod_set_myprop (myp_mymod_t *self, <type> myprop)
{
assert (self);
self->myprop = myprop;
}
[[/code]]
* Properties exposed by accessor methods MAY not actually exist as such in the instance; they may be calculated rather than simply copied to/from the instance structure.
++++ Formatted String Arguments
When a method (such as an accessor method) accepts a string argument as primary argument, it SHOULD use a variable argument list and perform vsnprintf formatting on that string argument.
++++ General Methods
The class MAY offer any number of other methods that operate on the instance. These methods shall take this general form:
* The first argument to the method SHALL be the instance reference.
* Other arguments may follow.
A method may take ownership of an object instance and then act as a destructor of the object instance at some later stage. In that case the method SHALL use the same style as the destructor.
++++ Return Values
Methods SHOULD use one of the following patterns for returning values to the caller:
* Returning nothing, if no return value is expected.
* Returning a property value, on an accessor method.
* Returning an object instance, on a constructor or duplicator.
* Returning a child value, on a list navigation method.
* Returning zero on success, -1 on failure.
* Returning a freshly-allocated string.
++ Code Style
+++ Thread Safety
* All methods SHALL be thread safe.
* Class instances SHOULD NOT generally be thread safe; a class instance will be owned by a single calling thread.
* In exceptional cases class instances MAY be made thread safe by the addition of mutexes or locks inside methods.
+++ Heap Use
One of the goals of CLASS is to hide heap use as far as possible within classes. Application programs SHOULD use the heap only through constructors and duplicators (including the library {{strdup ()}} function). Class methods MAY use the heap with care, but follow these rules:
* When a class instance has been destroyed, all heap memory it used MUST be freed. Classes SHALL NOT leak memory under any conditions except during abnormal termination (e.g., on a failed assertion).
* Non-atomic properties SHOULD be re-allocated (i.e., freed and allocated) in accessor functions that modify them, as needed.
* The instance structure MAY use char arrays instead of heap allocated char pointers.
* When freeing a non-atomic property outside the destructor, a method MUST set the property to null if it does not allocate a new value immediately.
+++ Static Variables
Classes SHOULD NOT use static variables except in exceptional cases, such as for global variables.
Static variables are not thread safe and they are therefore considered poor practice.
Particularly for representing any temporary state inside a class body, stack variables SHALL be used in place of static variables.
+++ Static Functions
Functions that are not exported by a class are defined as {{static}} and named {{s_functionname ()}} with no use of the project abbreviation or class name.
Static functions MAY be defined before first use, or MAY be prototyped and defined immediately after first use.
Static functions SHOULD NOT be collected at the end of the class source code.
++ Code Style
+++ Indentation
Indentation SHALL be 4 spaces per level. Tab characters SHALL NOT be used in code.
+++ Declarations
Functions SHALL be prototyped as follows:
[[code]]
<type>
<name> (<arguments>);
[[/code]]
Functions SHALL be defined as follows:
[[code]]
<type>
<name> (<arguments>)
{
<body>
}
[[/code]]
When the project uses C99, stack variables SHALL be defined in-line, as close as possible to their first use, and initialized. For example:
[[code]]
myp_mymod_t *mymod = myp_mymod_new ();
char *comma = strchr (surname, '.');
[[/code]]
When the project uses C89, stack variables SHALL all be defined and initialized at the start of the function or method where they are used.
* Variables and functions SHALL use lower-case names.
* Where necessary, underlines SHALL be used to separate parts of a name.
* Variable names like {{i}} and {{temp}} that carry no information SHALL NOT be used.
+++ Statements
Code lines of more than 80-100 characters SHOULD be folded for readability.
Single-statement blocks SHALL NOT be enclosed in brackets.
This is the form of a single-statement block:
[[code]]
if (comma == NULL)
comma = surname;
[[/code]]
In {{else}} statements, the {{else}} SHALL be put on a line by itself.
Multiple {{if}}/{{else}} tests SHALL be stacked vertically to indicate that the order is arbitrary.
This is the form of a stacked {{if}} statement block:
[[code]]
if (command == CMD_HELLO)
puts ("hello");
else
if (command == CMD_GOODBYE)
puts ("goodbye");
else
if (command == CMD_ERROR)
puts ("error");
[[/code]]
With multi-statement conditional blocks, the closing bracket SHALL be put on a line by itself, aligned with the opening keyword.
This is the form of a stacked {{if}} statement block with brackets around each conditional block:
[[code]]
if (command == CMD_HELLO) {
puts ("hello");
myp_peer_reply (peer, CMD_GOODBYE);
}
else
if (command == CMD_GOODBYE) {
puts ("goodbye");
myp_peer_reply (peer, CMD_DISCONNECT);
}
else
if (command == CMD_ERROR) {
puts ("error");
myp_peer_close (peer);
}
[[/code]]
This is the form of a {{while}} statement:
[[code]]
char *comma = strchr (surname, ',');
while (comma) {
*comma = ' ';
comma = strchr (surname, ',');
}
[[/code]]
+++ Comments
Comments on code SHALL be used lightly and where necessary.
In C99 projects the syntax for comments is:
* In-line comments SHALL use the C++ {{//}} style.
* Multi-line comments MAY use the C {{/* ... */}} style or MAY use the C++ style.
In C89 projects the syntax for all comments SHALL be the C {{/* ... */}} style.
* When possible in-line comments shall start at column 33.
* In in-line comments, the {{//}} or {{/*}} shall be followed by two spaces.
* Every function shall have a multi-line comment header that briefly explains its purpose.
* Method comment headers SHALL be preceded by a line of hyphens ending at column 78.
* Suitably-marked-up comments before a function MAY be used as source material for reference documentation.
This is the general template for a method comment header:
[[code]]
// --------------------------------------------------------------------------
// Finds the first item in the list, returns null if the list is empty.
myp_mymod_t *
myp_mymod_first (myp_mymod_t *self)
{
...
[[/code]]
* Every property in a class structure SHALL have a 1-line in-line comment that describes its purpose.
* Comments SHALL NOT be used to compensate for illegible code.
* Code that cannot be reasonable read and understood by the casual reader SHOULD be rewritten, not annotated.
* Properties and functions whose semantics are not clear from their names SHOULD be renamed, not annotated.
+++ Blank Lines
Blank lines SHALL be used to separate blocks of code to improve readability, in these cases:
* After the closing bracket of a function body and before the comment header for a function.
* To break up blocks of code that exceed 6-8 lines.
* After assertions at the start of a class body.
* After an {{if}} statement with a single-statement block.
* After multi-line {{case}} blocks inside a {{switch}} statement.
* After multi-line comment blocks.
Blank lines SHALL not be used in these cases:
* After the closing bracket of a conditional block.
* To separate individual lines of code that could better be grouped together.
+++ Vertical Alignment
Code SHALL NOT use extra spacing to create vertical alignment.
[[code]]
char *comma = strchr (surname, ',');
while (comma) {
*comma = ' ';
comma = strchr (surname, ',');
}
[[/code]]
+++ Punctuation
Punctuation SHALL follow English rules as far as possible.
This is the style for unary operators, with a space after but not before the operator:
[[code]]
char_nbr++;
[[/code]]
This is the style for binary operators, with a space before and after the operator:
[[code]]
comma = comma + 1;
[[/code]]
This is the style for the {{?:}} operator:
[[code]]
comma = comma? comma + 1: strchr (name, '.');
[[/code]]
This is the style for semi-colons, with a space after but not before:
[[code]]
for (char_nbr = 0; *char_nbr; char_nbr++)
char_nbr++;
[[/code]]
This is the style for parentheses, with a space before the opening, and after the closing parenthesis, with multiple opening or closing parentheses joined together without spaces:
[[code]]
node = (node_t *) zmalloc (sizeof (node_t));
if (!node)
return -1;
[[/code]]
This is the style for square brackets:
[[code]]
comma = name [char_nbr];
[[/code]]
This is the style for pointer dereferences, with no space before or after the '->':
[[code]]
self->name = strdup (name);
[[/code]]
+++ Assertions
Classes SHOULD check the validity of arguments using assertions. That is, misuse of the API is considered a programming error, not a run-time error.
* Assertions SHALL be used for their documentary value, for example to warn the reader, "this argument SHALL NOT be null".
* Assertions on arguments SHALL come at the start of the class body and SHALL follow the order of the arguments.
* Assertions MAY be used on return values from function calls if such failures cannot safely be handled by the code.
* Assertions MAY be used on internal state (e.g., instance properties) to assert a mandatory condition for continuing.
* Assertions SHALL NOT be used to trap errors on external conditions, e.g., bad user input, invalid protocol messages, etc.
* Assertions SHOULD be used to trap errors on internal APIs, e.g. invalid messages sent from one thread to another.
* Assertions SHALL NOT have side-effects since the entire statement may be removed by an optimizing compiler.
+++ Exiting Functions and Goto Statements
The {{return}} statement MAY be used at any point in a function to return to the caller.
If the function needs to do clean-up (e.g., free a number of properties), the code MAY use {{goto}} and a single clean-up block at the end of the function. Such a clean-up block SHALL follow the last "normal" return.
A void function SHALL NOT end in an empty {{return}} statement.
+++ Recommended Patterns
* The recommended pattern for an open-ended loop is {{while (true) {}}, with {{break}} statements as needed to exit the loop.
* The recommended pattern for array iteration is:
[[code]]
for (array_index = 0; array_index < array_size; array_index++) {
// Access element [array_index]
}
[[/code]]
* The recommended pattern for list iteration is:
[[code]]
<type>
[[/code]]
++ Portability
+++ Portable Versus Native Classes
All projects SHALL depend at least on ZeroMQ (libzmq) and CZMQ (libczmq), which provide portable APIs around networking, threads, file systems, and other aspects.
* A class SHALL be either "portable" or "native".
* A portable class SHALL NOT use the preprocessor to compile differently on different systems.
* A native class SHALL export a properly abstracted API that hides system differences, and SHALL use the preprocessor to compile differently on different systems.
* A native class SHALL use the preprocessor macros defined in {{czmq_prelude.h}}, and specifically the {{__WINDOWS__}}, {{__UNIX__}}, and {{__UTYPE_ABC}} macros.
* A native class SHALL NOT use preprocessor macros supplied by any specific build system. If the CZMQ-supplied macros are not sufficient these can be improved and extended.
* The project architect SHOULD aim to fully separate portable and native classes, so that application developers see and write only portable classes.
This example shows the general style of native code:
[[code]]
#if (defined (__UNIX__))
pid = GetCurrentProcessId ();
#elif (defined (__WINDOWS__))
pid = getpid ();
#else
pid = 0;
#endif
[[/code]]
+++ Portable Language
The following types and macros are defined by CZMQ and may be used safely in all code:
* {{bool}}, {{true}}, {{false}}: Boolean data type and constants.
* {{byte}}, {{dbyte}}, {{qbyte}}: unsigned 1-, 2-, and 4-octet integers.
* {{uint}}, {{ulong}}: unsigned integers and longs.
* {{int32_t}}, {{int64_t}}: signed 32-bit and 64-bit integers.
* {{uint32_t}}, {{uint64_t}}: unsigned 32-bit and 64-bit integers.
* {{streq (s1, s2)}}: preferred over {{strcmp (s1, s2) == 0}}.
* {{strneq (s1, s2)}}: preferred over {{strcmp (s1, s2) != 0}}.
* {{randof (number)}}: return random integer in range 0 .. number - 1.
* {{srandom}}: typically used like this: {{srandom ((unsigned) time (NULL));}}
* {{inline}}, {{snprintf}}, {{vsnprintf}}: Windows uses non-POSIX variants with underscores.
+++ Compiler Warnings
Compiler warnings SHOULD always be treated as fatal. The following is a list of constructs known to cause warnings on some but not all compilers:
* Assigning a void pointed to a typed pointer without a cast. Always cast a void * before assigning it to a typed pointer.
* Failing to return a value in a non-void function. Always end a non-void function with a {{return}} statement.
++ Code Generation
Code generation MAY be used to produce classes mechanically when there is compelling benefit.
* The code generator SHOULD be GSL, from https://github.com/imatix/gsl.
* All code generation scripts SHALL be in the project {{scripts}} subdirectory.
* All model data (XML files) SHALL be in the project {{model}} directory.
* The {{model}} directory SHALL contain a shell script {{generate}} that performs the code generation. The general model for this script is:
[[code]]
export PATH=../scripts:$PATH
gsl -q -script:<script>.gsl <model>.xml
[[/code]]
* If only parts of a class are generated, these parts SHALL have the extension {{.inc}} and SHALL ge generated into the project {{src}} directory, and SHALL be included in the class source file using an #include statement.
* Code generation SHALL be done manually, and all generated code SHALL be committed into the project as for hand-written files.
* Code generation SHALL be fully idempotent, that is, generated code SHALL NOT contain any date or time stamps.
* Code generation SHALL be treated as a form of dangerous abstraction that creates significant barriers to readers. A good rule of thumb is that for code generation to be profitable, it should reduce the lines of code written by hand by 80-90%.
* Generated code SHALL contain this warning at the start: "GENERATED SOURCE CODE, DO NOT EDIT".
* Generated code SHALL otherwise conform to this Specification so that it is indistinguishable from hand-written code.
++ Security Aspects
+++ Thread Safety
The use of opaque data structures that are accessed via references is thread safe. However:
* Code SHALL NOT share state between threads except in exceptional and limited cases. Threads SHALL communicate by passing 0MQ messages.
* Classes SHALL not use static variables since this is not re-entrant, thus not thread safe.
* Class instances SHALL NOT be passed between threads except in "hand-off" cases.
* Code SHOULD NOT use mutexes, locks, or other mechanisms to share state between threads.
* Code MUST NOT use non-thread safe system calls such as {{basename ()}}.
+++ Buffer Overflows
* Code MUST always truncate over-long data.
* Code MUST NOT use unsafe system calls such as {{gets ()}}.
+++ Known Weaknesses
* The heavy reliance on heap memory means that CLASS applications are vulnerable to denial-of-service attacks. Applications can mitigate this risk by enforcing limits on the number of class instances they create.