1Clownfish::Docs::WritinUgsCelrasCsoenst(r3i)buted Perl DColcouwmnefnitsaht:i:oDnocs::WritingClasses(3)
2
3
4
6 Clownfish::Docs::WritingClasses - Writing Apache Clownfish classes
7
9 Parcels
10 Every Clownfish class belongs to a Clownfish parcel. Parcels are used
11 for namespacing and versioning. Information about parcels is stored in
12 ".cfp" files which contain a JSON hash with the following keys:
13
14 • name: The parcel’s name. It must contain only letters.
15
16 • nickname: A short nickname. It must contain only letters. This
17 nickname, followed by an underscore, is used to prefix generated C
18 symbols and macros. Depending on the kind of symbol, a lowercase or
19 uppercase prefix will be used.
20
21 • version: A version specifier of the following form (without
22 whitespace):
23
24 version-specifier = "v" version-number
25 version-number = digit+ | digit+ "." version-number
26
27 • prerequisites: A hash containing the prerequisite parcels. The hash
28 keys are the parcel names. The values contain the minimum required
29 version.
30
31 An example ".cfp" file might look like:
32
33 {
34 "name": "Pathfinder",
35 "nickname": "Pfind",
36 "version": "v2.3.8",
37 "prerequisites": {
38 "Clownfish": "v0.6.3"
39 }
40 }
41
42 A parcel specifier of the following form is used in Clownfish header
43 files:
44
45 parcel-specifier = "parcel" parcel-name ";"
46 parcel-name = identifier
47
48 For example:
49
50 parcel Pathfinder;
51
52 Every ".cfh" file starts with a parcel specifier containing the name of
53 the parcel for all classes in the header file.
54
55 Initialization
56
57 Every Clownfish parcel must be initialized before it is used. The
58 initialization function is named "{parcel_nick}_bootstrap_parcel" and
59 takes no arguments.
60
61 Example call:
62
63 pfind_bootstrap_parcel();
64
65 The generated host language bindings call the bootstrap function
66 automatically. C projects must call the function manually.
67
68 Short names
69
70 If a macro with the uppercase name "{PARCEL_NICK}_USE_SHORT_NAMES" is
71 defined before including a generated C header, additional macros
72 without the parcel prefix will be defined for most symbols.
73
74 Example:
75
76 #define PFIND_USE_SHORT_NAMES
77 #include <Pathfinder/Graph.h>
78 #include <Pathfinder/Path.h>
79
80 /* Prefixes can be omitted. */
81 Path *path = Graph_Find_Shortest_Path(graph);
82
83 /* Without PFIND_USE_SHORT_NAMES, one would have to write: */
84 pfind_Path *path = PFIND_Graph_Find_Shortest_Path(graph);
85
86 For object types in Clownfish header files, prefixes of class structs
87 can also be omitted unless multiple parcels declare classes with the
88 same last component of the class name.
89
90 The “Clownfish” parcel
91
92 The Clownfish runtime classes live in a parcel named "Clownfish" with
93 nickname "Cfish". Consequently, the short name macro is named
94 "CFISH_USE_SHORT_NAMES".
95
96 Declaring classes
97 Classes are declared in Clownfish header files using a declaration of
98 the following form:
99
100 class-declaration = class-exposure-specifier?
101 class-modifier*
102 "class" class-name
103 ("nickname" class-nickname)?
104 ("inherits" class-name)?
105 "{" class-contents "}"
106 class-exposure-specifier = "public"
107 class-modifier = "inert" | "final"
108 class-name = identifier | identifier "::" class-name
109 class-nickname = identifier
110 class-contents = (variable-declaration | function-declaration)*
111
112 Class name components must start with an uppercase letter and must not
113 contain underscores. The last component must contain at least one
114 lowercase letter and must be unique for every class in a parcel.
115
116 For every class, a type with the name "{parcel_nick}_{Class_Last_Comp}"
117 is defined in the generated C header. This is an opaque typedef used to
118 ensure type safety.
119
120 For every class, a global variable with the uppercase name
121 "{PARCEL_NICK}_{CLASS_LAST_COMP}" is defined. This variable is a
122 pointer to a Clownfish::Class object which is initialized when
123 bootstrapping the parcel.
124
125 Non-inert classes inherit from Clownfish::Obj by default.
126
127 Example of a class declaration:
128
129 parcel Pathfinder;
130
131 public class Pathfinder::Graph::VisibilityGraph nickname VisGraph
132 extends Clownfish::Obj {
133 /* Variables and functions */
134 }
135
136 This will generate:
137
138 typedef struct pfind_VisibilityGraph pfind_VisibilityGraph;
139 extern cfish_Class *PFIND_VISIBILITYGRAPH;
140
141 Class exposure
142
143 API documentation will only be generated for classes with "public"
144 exposure.
145
146 Inert classes
147
148 Inert classes must contain only inert variables or inert functions,
149 that is, neither instance variables nor methods. They must not inherit
150 from another class nor be inherited from. They’re essentially nothing
151 more than a namespace for functions and global variables.
152
153 Final classes
154
155 For final classes, every method is made final, regardless of the method
156 modifier. Final classes must not be inherited from.
157
158 Variables
159 Variables are declared with a declaration of the following form:
160
161 variable-declaration = variable-modifier*
162 type variable-name ";"
163 variable-modifier = "inert"
164 variable-name = identifier
165
166 Inert variables
167
168 Inert variables are global class variables of which only a single copy
169 exists. They are declared in the generated C header with the name
170 "{parcel_nick}_{Class_Nick}_{Variable_Name}" and must be defined in a C
171 source file.
172
173 Example:
174
175 public class Pathfinder::Path {
176 public inert int max_path_length;
177 }
178
179 This will generate:
180
181 extern int pfind_Path_max_path_length;
182
183 The C source file defining the variable will typically use short names.
184 So the definition will look like:
185
186 int Path_max_path_length = 5000;
187
188 Instance variables
189
190 Non-inert variables are instance variables and added to the class’s
191 ivars struct.
192
193 Example:
194
195 public class Pathfinder::Path {
196 int num_nodes;
197
198 public int
199 Get_Num_Nodes(Path *self);
200 }
201
202 This will add a "num_nodes" member to the ivars struct of "Path".
203
204 The ivars struct
205
206 To access instance variables, the macro
207 "C_{PARCEL_NICK}_{CLASS_LAST_COMP}" must be defined before including
208 the generated header file. This will make a struct named
209 "{parcel_nick}_{Class_Name}IVARS" with a corresponding typedef and
210 short name available that contains all instance variables of the class
211 and all superclasses from the same parcel. Instance variables defined
212 in other parcels are not accessible. This is by design to guarantee ABI
213 stability if the instance variable layout of a superclass from another
214 parcel changes in a different version. If you need to access an
215 instance variable from another parcel, add accessor methods.
216
217 A pointer to the ivars struct can be obtained by calling an inline
218 function named "{parcel_nick}_{Class_Name}_IVARS". This function takes
219 the object of the class (typically "self") as argument.
220
221 Example using short names:
222
223 #define C_PFIND_PATH
224 #define PFIND_USE_SHORT_NAMES
225 #include "Pathfinder/Path.h"
226
227 int
228 Path_get_num_nodes(Path *self) {
229 PathIVARS *ivars = Path_IVARS(self);
230 return ivars->num_nodes;
231 }
232
233 Functions
234 function-declaration = function-exposure-specifier?
235 function-modifier*
236 return-type function-name
237 "(" param-list? ")" ";"
238 function-exposure-specifier = "public"
239 function-modifier = "inert" | "inline" | "abstract" | "final"
240 return-type = return-type-qualifier* type
241 return-type-qualifier = "incremented" | "nullable"
242 function-name = identifier
243 param-list = param | param "," param-list
244 param = param-qualifier* type param-name ("=" scalar-constant)?
245 param-name = identifier
246 param-qualifier = "decremented"
247
248 Function exposure
249
250 API documentation will only be generated for functions with "public"
251 exposure.
252
253 Inert functions
254
255 Inert functions are dispatched statically. They are declared in the
256 generated C header with the name
257 "{parcel_nick}_{Class_Nick}_{Function_Name}" and must be defined in a C
258 source file. They must be neither abstract nor final.
259
260 Example:
261
262 public class Pathfinder::Graph::VisibilityGraph nickname VisGraph
263 extends Clownfish::Obj {
264
265 public inert incremented VisibilityGraph*
266 new(int node_capacity);
267 }
268
269 This will generate:
270
271 pfind_VisibilityGraph*
272 pfind_VisGraph_new(int node_capacity);
273
274 The C source file implementing the inert function will typically use
275 short names. So the implementation will look like:
276
277 #define PFIND_USE_SHORT_NAMES
278 #include "Pathfinder/Graph/VisibilityGraph.h"
279
280 VisibilityGraph*
281 VisGraph_new(int node_capacity) {
282 /* Implementation */
283 }
284
285 Inline functions
286
287 Inert functions can be inline. They should be defined as static inline
288 functions in a C block in the Clownfish header file. The macro
289 "CFISH_INLINE" expands to the C compiler’s inline keyword and should be
290 used for portability.
291
292 Methods
293
294 Non-inert functions are dynamically dispatched methods. Their name must
295 start with an uppercase letter and every underscore must be followed by
296 an uppercase letter. Methods must not be declared inline.
297
298 The first parameter of a method must be a pointer to an object of the
299 method’s class which receives the object on which the method was
300 invoked. By convention, this parameter is named "self".
301
302 For every method, an inline wrapper for dynamic dispatch is defined in
303 the generated C header with the name
304 "{PARCEL_NICK}_{Class_Nick}_{Method_Name}". Additionally, an
305 implementing function is declared with the name
306 "{PARCEL_NICK}_{Class_Nick}_{Method_Name}_IMP". The Clownfish compiler
307 also generates a typedef for the method’s function pointer type named
308 "{PARCEL_NICK}_{Class_Nick}_{Method_Name}_t". Wrappers and typedefs are
309 created for all subclasses whether they override a method or not.
310
311 Example:
312
313 public class Pathfinder::Graph::VisibilityGraph nickname VisGraph
314 extends Clownfish::Obj {
315
316 public void
317 Add_Node(VisibilityGraph *self, decremented Node *node);
318 }
319
320 This will generate:
321
322 /* Wrapper for dynamic dispatch */
323 static inline void
324 PFIND_VisGraph_Add_Node(pfind_VisibilityGraph *self, pfind_Node *node) {
325 /* Inline code for wrapper */
326 }
327
328 /* Declaration of implementing function */
329 void
330 PFIND_VisGraph_Add_Node_IMP(pfind_VisibilityGraph *self,
331 pfind_Node *node);
332
333 /* Declaration of function pointer type */
334 typedef void
335 (*PFIND_VisGraph_Add_Node_t)(pfind_VisibilityGraph *self,
336 pfind_Node *node);
337
338 The implementing function of non-abstract methods must be defined in a
339 C source file. This file will typically define the short names macro.
340 So the implementation will look like:
341
342 #define PFIND_USE_SHORT_NAMES
343 #include "Pathfinder/Graph/VisibilityGraph.h"
344
345 void
346 VisGraph_Add_Node_IMP(VisibilityGraph *self, Node *node) {
347 /* Implementation */
348 }
349
350 Looking up methods
351
352 Clownfish defines a macro named "CFISH_METHOD_PTR" that looks up the
353 pointer to the implementing function of a method. The first parameter
354 of the macro is a pointer to the Clownfish::Class object of the
355 method’s class, the second is the unshortened name of the method
356 wrapper. If short names for the Clownfish parcel are used, the macro is
357 also available under the name "METHOD_PTR".
358
359 To lookup methods from a superclass, there’s a macro
360 "CFISH_SUPER_METHOD_PTR" with the same parameters.
361
362 Example using short names:
363
364 // Note that the name of the method wrapper must not be shortened.
365 VisGraph_Add_Node_t add_node
366 = METHOD_PTR(VISIBILITYGRAPH, Pfind_VisGraph_Add_Node);
367
368 VisGraph_Add_Node_t super_add_node
369 = SUPER_METHOD_PTR(VISIBILITYGRAPH, Pfind_VisGraph_Add_Node);
370
371 Abstract methods
372
373 For abstract methods, the Clownfish compiler generates an implementing
374 function which throws an error. They should be overridden in a
375 subclass.
376
377 Final methods
378
379 Final methods must not be overridden. They must not be abstract.
380
381 Nullable return type
382
383 If a function has a nullable return type, it must return a pointer.
384 Non-nullable functions must never return the NULL pointer.
385
386 Incremented return type
387
388 Incremented return types must be pointers to Clownfish objects. The
389 function will either return a new object with an initial reference
390 count of 1 or increment the reference count. The caller must decrement
391 the reference count of the returned object when it’s no longer used.
392
393 For returned objects with non-incremented return type, usually no
394 additional handling of reference counts is required. Only if an object
395 is returned from an accessor or a container object and the caller wants
396 to use the object longer than the returning object retains a reference,
397 it must increment the reference count itself and decrement when the
398 object is no longer used.
399
400 Decremented parameters
401
402 Decremented parameters must be pointers to Clownfish objects. The
403 function will either decrement the reference count of the passed-in
404 object or retain a reference without incrementing the reference count.
405 If the caller wants to use the passed-in object afterwards, it usually
406 must increment its reference count before the call and decrement it
407 when it’s no longer used. If the caller does not make further use of
408 the passed-in object, it must not decrement its reference count after
409 the call.
410
411 This is typically used in container classes like Vector:
412
413 String *string = String_newf("Hello");
414 Vec_Push(array, (Obj*)string);
415 // No need to DECREF the string.
416
417 Default parameter values
418
419 Default parameter values can be given as integer, float, or string
420 literals. The values "true", "false", and "NULL" are also supported.
421 The default values are only used by certain host language bindings.
422 They’re not supported when calling a function from C.
423
424 C blocks
425 Clownfish headers can contain C blocks which start with a line
426 containing the string "__C__" and end on a line containing the string
427 "__END_C__". The contents of a C block are copied verbatim to the
428 generated C header.
429
430 Example:
431
432 __C__
433
434 struct pfind_AuxiliaryStruct {
435 int a;
436 int b;
437 };
438
439 __END_C__
440
441 Object life cycle
442 Object creation
443
444 Objects are allocated by invoking the "Make_Obj" method on a class’s
445 Clownfish::Class object.
446
447 Any inert function can be used to construct objects from C. But to
448 support inheritance and object creation from the host language,
449 Clownfish classes need a separate function to initialize objects. The
450 initializer must take a pointer to an object as first argument and
451 return a pointer to the same object. If the parent class has an
452 initializer, it should be called first by the subclass’s initializer.
453
454 By convention, the standard constructor is named "new" and the standard
455 initializer "init".
456
457 Example:
458
459 /* Clownfish header */
460
461 class Vehicle {
462 double max_speed;
463
464 inert Vehicle*
465 init(Vehicle *self, double max_speed);
466 }
467
468 class Train inherits Vehicle {
469 double track_gauge;
470
471 inert incremented Train*
472 new(double max_speed, double track_gauge);
473
474 inert Train*
475 init(Train *self, double max_speed, double track_gauge);
476 }
477
478 /* Implementation */
479
480 Train*
481 Train_new(double max_speed, double track_gauge) {
482 Train *self = (Train*)Class_Make_Obj(TRAIN);
483 return Train_init(self, max_speed, track_gauge);
484 }
485
486 Train*
487 Train_init(Train *self, double max_speed, double track_gauge) {
488 Vehicle_init((Vehicle*)self, max_speed);
489 self->track_gauge = track_gauge;
490 return self;
491 }
492
493 Reference counting
494
495 Clownfish uses reference counting for memory management. Objects are
496 created with a reference count of 1. There are two macros
497 "CFISH_INCREF" and "CFISH_DECREF" to increment and decrement reference
498 counts. If short names for the Clownfish parcel are enabled, the macros
499 can be abbreviated to "INCREF" and "DECREF". Both macros take a pointer
500 to an object as argument. NULL pointers are allowed. "CFISH_INCREF"
501 returns a pointer to the object. This value might differ from the
502 passed-in pointer in some cases. So if a reference is retained, the
503 pointer returned from "CFISH_INCREF" should be used. "CFISH_DECREF"
504 returns the modified reference count.
505
506 Examples:
507
508 self->value = INCREF(arg);
509
510 DECREF(object);
511
512 Object destruction
513
514 If an object’s reference count reaches 0, its "Destroy" method is
515 called. This public method takes no arguments besides "self" and has
516 no return value. It should release the resources held by the object
517 and finally call the "Destroy" method of the superclass via the
518 "CFISH_SUPER_DESTROY" macro with short name "SUPER_DESTROY". This macro
519 takes the "self" pointer as first argument and a pointer to the
520 object’s Clownfish::Class as second argument. The "Destroy" method of
521 the Clownfish::Obj class will eventually free the object struct.
522
523 Example:
524
525 /* Clownfish header */
526
527 class Path {
528 Vector *nodes;
529
530 public void
531 Destroy(Path *self);
532 }
533
534 /* Implementation */
535
536 void
537 Path_Destroy_IMP(Path *self) {
538 DECREF(self->nodes);
539 SUPER_DESTROY(self, PATH);
540 }
541
542 Documentation
543 The Clownfish compiler creates documentation in the host language’s
544 preferred format from so-called DocuComments found in the ".cfh" files.
545 DocuComments use Markdown (CommonMark <http://commonmark.org/> flavor)
546 for formatting. DocuComments are multi-line C-style comments that
547 start with "/**". They immediately precede the documented class, inert
548 function, or method. A left border consisting of whitespace and
549 asterisks is stripped.
550
551 The DocuComment for a class should start with a short description
552 (everything up until the first period ".") which may appear in the name
553 section of a man page, for example.
554
555 DocuComments for functions and methods may end with a series of @param
556 and @return directives which document the parameters and return values.
557
558 Example:
559
560 /** Class describing a train.
561 *
562 * The Train class describes a train. It extends the Vehicle class and
563 * adds some useful properties specific to trains.
564 */
565 public class Train inherits Vehicle {
566 /** Create a new Train object.
567 *
568 * @param max_speed The maximum speed in km/h.
569 * @param track_gauge The track gauge in mm.
570 */
571 public inert incremented Train*
572 new(double max_speed, double track_gauge);
573
574 /** Accessor for maximum speed.
575 *
576 * @return the maximum speed in km/h.
577 */
578 public double
579 Get_Max_Speed(Train *self);
580 }
581
582 The Clownfish compiler also looks for standalone Markdown ".md" files
583 in the source directories which will be included in the documentation.
584
585
586
587perl v5.36.0 2023-01-20Clownfish::Docs::WritingClasses(3)