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
|
CODING STYLE REQUIREMENTS
Copyright (c) 2011-2017 Oleh Derevenko
This article is provided to you under the terms of Artistic License 2.0
(http://www.opensource.org/licenses/artistic-license-2.0).
(I) General Coding Requirements
=============================================================================
1. Not more than one complex construction per function
----------------------------------------------------------------------------
A function must not contain more than one* operator from the following set:
for, while, do..while, switch and constructions try..catch, try..finally.
Moreover, those operators/constructions must not appear inside of a
conditional operator.
* Loop inclusion is allowed if multi-dimensional array must be iterated and
all the elements are uniform and need to be processed linearly.
try..finally construction inclusion is allowed for several resource
allocations that need to be performed together.
2. Absence of jumps
----------------------------------------------------------------------------
goto and continue operators must not be used.
3. Single exit point at the end of function
----------------------------------------------------------------------------
A function must not have other exit points except for the end of its
definition. If a function returns a value, return operator must be the last
syntactical construction in the function.
4. Zero value means failure
----------------------------------------------------------------------------
Function results must be chosen the way that binary zero value had a meaning
of failure. Similarly, types must be designed so that binary zero element
had the meaning of an invalid value (if invalid element concept is applicable
for the type).
5. Variables and parameters are initialized with zeroes
----------------------------------------------------------------------------
Variables and class fields must be initialized with values of binary zero
presentation. Public enumerated types must be designed to have zero element
and that element is to be the default element. Function default parameters
must be chosen in the form to have binary zero value.
6. Variables are not reused
----------------------------------------------------------------------------
Variables must not be reused for other purposes after they have already been
used for something. The only value that might be stored in a variable is that
described with its name.
7. Parameters passed by value are treated as constants
----------------------------------------------------------------------------
Parameters that are passed by value must not be modified*. All of them must
be treated as if they have been implicitly declared with const modifier.
* An exception could be the case when a value loses its meaning (e.g. a
pointer to an object being deleted).
8. Result assignment is performed at the end of function
----------------------------------------------------------------------------
Every function returning a result must have a variable to contain the result
of that function. It is to be declared (initialized if necessary) at the
beginning of the function* and the only access to it after that should be its
final value assignment. The assignment should be the last meaningful operator
in an execution branch**. Several assignments, one per each execution branch,
are allowed.
* It is allowed to declare result variable with assignment immediately before
return operator.
** It is allowed to include technical constructions like logging or
performance measuring after result variable assignment.
9. Parameters by reference are not used in expressions
----------------------------------------------------------------------------
Parameters of simple types passed by reference must be copied into local
variables at function entry and then be assigned their final values at
function exit.
Output parameters can be initialized at function entry and must be assigned
their final values immediately before the function result variable assignment.
(II) Class Design Requirements
=============================================================================
1. Classes work with their fields on their own
----------------------------------------------------------------------------
A function or method must not call several methods of other class, some of
them being used to return and the others being used to assign the class fields.
Such a code must be implemented as a method of that other class.
2. No direct access to the fields
----------------------------------------------------------------------------
All the work with class fields (including fields of own class) must be
performed with aid of dedicated methods (accessors) that return and assign
field values. Exceptions can be made for constructors/destructors and methods
dedicated for field initialization/finalization.
3. Private fields only
----------------------------------------------------------------------------
All class fields must be private.
4. No code in constructors and destructors
----------------------------------------------------------------------------
Class constructors must not have raw code other than doing trivial field
initialization. If creation of contained objects is necessary or other
operations need to be done they are to be performed via calls to the class
methods rather than placed directly in constructor. Initial zero-assignment
to a field is always required even if that field is later to be
unconditionally assigned in methods called from the constructor.
Similarly, a destructor must free contained objects with calls to the class
methods rather than containing that code inline.
5. No code in callbacks
----------------------------------------------------------------------------
Event handlers, callback interface methods and static callback methods must
not have meaningful code within them. Their implementation should validate
input arguments, convert them to proper internal types if necessary, and call
one or more other methods of the class. These methods must not be declated in
public section.
6. No public virtual methods
----------------------------------------------------------------------------
Methods declared as virtual must not be public. The public calls to such
methods must be wrapped with ordinary class methods.
7. No logical level violations
----------------------------------------------------------------------------
Methods of lower logical levels must not call any methods of higher logical
levels of the class. In particular, methods declared as protected and private
must not call methods declared in public sections of own or ancestor classes.
Methods declared as public may only call protected and private methods.
Similarly classes of lower logical levels must not call public methods of
classes at higher logical levels. Such calls are only possible via dedicated
callback methods or callback interfaces.
(III) Canonical Function Structures
=============================================================================
0. Preamble
----------------------------------------------------------------------------
Following are general function structures encouraged to be used for coding
all the program logic. Any algorithm with branching can be implemented
with these types of functions.
Using these function structures helps to make code clear and error-proof.
1. A Boolean Function
----------------------------------------------------------------------------
The Boolean Function can be used to implement algorithms with conditional
branching.
bool PerformSomeAction(...)
{
bool bResult = false;
// Some linear code
if (...)
{
// Some linear code
if (...) // Optionally...
{
bResult = true;
}
}
// Optionally...
else if (...)
{
// Some linear code
bResult = true;
}
return bResult;
}
The idea is to have result variable initialized with false at entry and then
have an arbitrary structure of conditional operators with some branches
changing result variable to true on exit.
2. A Validation Function
----------------------------------------------------------------------------
The Validation Function is an alternative to Boolean Function to implement
conditional logic. It's mostly convenient for implementing multi-step
algorithms that may fail (like validations or initializations of multiple
items of non-uniform nature).
bool PerformSomeValidation(...)
{
bool bResult = false;
do
{
// Some linear code
// Optionally...
if ( !(...) )
{
// Some error handling // Optionally...
break;
}
// Optionally...
if (...)
{
// Some linear code
if ( !(...) )
{
// Some error handling // Optionally...
break;
}
// Some linear code
}
bResult = true;
}
while (false);
return bResult;
}
If function execution has side effects which need to be rolled back in case
of failures on subsequent steps the function structure can be altered to the
following form.
bool PerformSomeInitialization(...)
{
bool bResult = false;
bool bFirstSideEffectApplied = false, bSecondSideEffectApplied = false, ...;
do
{
// Some linear code
if ( !ExecuteFirstSideEffectApplication(...) )
{
// Some error handling // Optionally...
break;
}
bFirstSideEffectApplied = true
// Some linear code
if ( !ExecuteSecondSideEffectApplication(...) )
{
// Some error handling // Optionally...
break;
}
bSecondSideEffectApplied = true
...
// Some linear code
if ( !ExecuteLastSideEffectApplication(...) )
{
// Some error handling // Optionally...
break;
}
bResult = true;
}
while (false);
if (!bResult)
{
if (bFirstSideEffectApplied)
{
if (bSecondSideEffectApplied)
{
if (...)
{
...
}
ExecuteSecondSideEffectRollback(...);
}
ExecuteFirstSideEffectRollback(...);
}
}
return bResult;
}
3. A Loop Validation Function
----------------------------------------------------------------------------
The Loop Validation Function can be used for processing sequences of items
while the processing of each or some individual items can fail.
bool PerformLoopValidation(...)
{
bool bAnyFailure = false;
for (...) // Or any other loop control operator
{
// Some linear code
if ( !(...) )
{
// Some error handling // Optional
bAnyFailure = true;
break;
}
// Some linear code
}
bool bResult = !bAnyFailure;
return bResult;
}
In case if a loop processing function may apply side effects on each step
which need to be reverted in case of a failure on subsequent steps the
functions need to be organized in the following four-function two-level
structure.
bool PerformLoopInitialization(...)
{
bool bResult = false;
size_t nFailureItem;
if (DoPerformLoopInitialization(..., nFailureItem))
{
bResult = true;
}
else
{
DoPerformLoopFinalization(..., nFailureItem);
}
return bResult;
}
void PerformLoopFinalization(...)
{
DoPerformLoopFinalization(..., npos); // Here "npos" stands for the invalid item index
}
bool DoPerformLoopInitialization(..., size_t &nOutFailureItem)
{
bool bAnyFailure = false;
size_t nOutFailureItem = npos;
for (...) // Or any other loop control operator
{
// Some linear code
if ( !(...) )
{
// Some error handling // Optional
nOutFailureItem = ...;
bAnyFailure = true;
break;
}
// Some linear code
}
bool bResult = !bAnyFailure;
return bResult;
}
void DoPerformLoopFinalization(..., size_t nExternalFinalizationEndItem/*=npos*/)
{
size_t nFinalizationEndItem = nExternalFinalizationEndItem == npos
? ... /* total item count */
: nExternalFinalizationEndItem;
for (... /* loop until nFinalizationEndItem */) // Or any other loop control operator
{
// Some linear code
RevertLoopItemSideEffects(...);
}
}
|