| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| =head1 NAME |
| |
| Clownfish - Symbiotic object system. |
| |
| =head1 VERSION |
| |
| 0.4.1 |
| |
| =head1 DESCRIPTION |
| |
| Clownfish is a "symbiotic" object system for C which is designed to pair |
| with a "host" dynamic language environment, facilitating the development |
| of high performance host language extensions. Clownfish classes are |
| declared in header files with a C<.cfh> extension. The Clownfish headers |
| are used by the Clownfish compiler to generate C header files and host |
| language bindings. Methods, functions and variables are defined in normal |
| C source files. |
| |
| =head2 Features |
| |
| =over |
| |
| =item * |
| |
| Designed to support multiple host languages. Currently, only Perl is supported. |
| |
| =item * |
| |
| Support for stand-alone C libraries and executables. |
| |
| =item * |
| |
| Subclassing and method overriding from the host language. |
| |
| =item * |
| |
| Support for host language idioms like named parameters or default argument |
| values. |
| |
| =item * |
| |
| Highly performant object system with lazy creation of host language objects. |
| |
| =item * |
| |
| Runtime with classes for commonly used data structures like strings, dynamic |
| arrays and hash tables. |
| |
| =item * |
| |
| Modularity. |
| |
| =item * |
| |
| Introspection. |
| |
| =item * |
| |
| Documentation generator. |
| |
| =back |
| |
| =head2 Planned features |
| |
| =over |
| |
| =item * |
| |
| Support for more host languages. |
| |
| =item * |
| |
| Guaranteed ABI stability when adding or reordering methods or instance |
| variables. |
| |
| =back |
| |
| =head1 USING CLOWNFISH CLASSES |
| |
| TODO: Simple introduction |
| |
| =head1 WRITING CLOWNFISH CLASSES |
| |
| =head2 Parcels |
| |
| Every Clownfish class belongs to a Clownfish parcel. Parcels are used for |
| namespacing and versioning. Information about parcels is stored in C<.cfp> |
| files which contain a JSON hash with the following keys: |
| |
| =over |
| |
| =item name |
| |
| The parcel's name. It must contain only letters. |
| |
| =item nickname |
| |
| A short nickname. It must contain only letters. This nickname, followed by an |
| underscore, is used to prefix generated C symbols and macros. Depending on the |
| kind of symbol, a lowercase, mixed case, or uppercase prefix will be used. |
| |
| =item version |
| |
| A version specifier of the following form (without whitespace): |
| |
| version-specifier = "v" version-number |
| version-number = digit | digit "." version-number |
| |
| =back |
| |
| An example C<.cfp> file might look like: |
| |
| { |
| "name": "Pathfinder", |
| "nickname": "Pfind", |
| "version": "v2.3.8" |
| } |
| |
| A parcel specifier of the following form is used in Clownfish header files: |
| |
| parcel-specifier = "parcel" parcel-name ";" |
| parcel-name = identifier |
| |
| For example: |
| |
| parcel Pathfinder; |
| |
| All classes following a parcel specifier will be associated with that parcel. |
| |
| =head3 Initialization |
| |
| Every Clownfish parcel must be initialized before it is used. The |
| initialization function is named C<{parcel_nick}_bootstrap_parcel> and takes |
| no arguments. |
| |
| Example call: |
| |
| pfind_bootstrap_parcel(); |
| |
| =head3 Short names |
| |
| If a macro with the uppercase name C<{PARCEL_NICK}_USE_SHORT_NAMES> is |
| defined before including a generated C header, additional macros without the |
| parcel prefix will be defined for most symbols. |
| |
| Example: |
| |
| #define PFIND_USE_SHORT_NAMES |
| #include <Pathfinder/Graph.h> |
| #include <Pathfinder/Path.h> |
| |
| /* Prefixes can be omitted. */ |
| Path *path = Graph_Find_Shortest_Path(graph); |
| |
| /* Without PFIND_USE_SHORT_NAMES, one would have to write: */ |
| pfind_Path *path = Pfind_Graph_Find_Shortest_Path(graph); |
| |
| For object types in Clownfish header files, prefixes of class structs can |
| also be omitted unless multiple parcels declare classes with the same last |
| component of the class name. |
| |
| =head3 The "Clownfish" parcel |
| |
| The Clownfish runtime classes live in a parcel named C<Clownfish> with |
| nickname C<Cfish>. Consequently, the short name macro is named |
| C<CFISH_USE_SHORT_NAMES>. |
| |
| =head2 Declaring classes |
| |
| Classes are declared in Clownfish header files using a declaration of the |
| following form: |
| |
| class-declaration = class-exposure-specifier? |
| class-modifier* |
| "class" class-name |
| ("nickname" class-nickname)? |
| ("inherits" class-name)? |
| "{" class-contents "}" |
| class-exposure-specifier = "public" |
| class-modifier = "inert" | "final" |
| class-name = identifier | identifier "::" class-name |
| class-nickname = identifier |
| class-contents = (variable-declaration | function-declaration)* |
| |
| Class name components must start with an uppercase letter and must not contain |
| underscores. The last component must contain at least one lowercase letter and |
| must be unique for every class in a parcel. |
| |
| For every class, a struct with the name C<{parcel_nick}_{Class_Last_Comp}> |
| and a corresponding typedef are declared in the generated C header. The struct |
| members are only visible if the uppercase macro |
| C<C_{PARCEL_NICK}_{CLASS_LAST_COMP}> is defined before including the header |
| file. |
| |
| For every class, a global variable with the uppercase name |
| C<{PARCEL_NICK}_{CLASS_LAST_COMP}> is defined. This variable is a pointer to |
| a Clownfish::Class object which is initialized when bootstrapping the parcel. |
| |
| Example of a class declaration: |
| |
| parcel Pathfinder; |
| |
| public class Pathfinder::Graph::VisibilityGraph nickname VisGraph |
| extends Clownfish::Obj { |
| /* Variables and functions */ |
| } |
| |
| This will generate: |
| |
| struct pfind_VisibilityGraph { |
| /* Instance variables */ |
| }; |
| typedef struct pfind_VisibilityGraph pfind_VisibilityGraph; |
| extern cfish_Class *PFIND_VISIBILITYGRAPH; |
| |
| =head3 Class exposure |
| |
| Classes without public exposure have parcel exposure. They are not visible |
| outside of the parcel and must not contain public variables or functions. |
| |
| =head3 Inert classes |
| |
| Inert classes must contain only inert variables or inert methods, that is, |
| neither instance variables nor methods. They must not inherit from another |
| class or be inherited from. Non-inert classes inherit from Clownfish::Obj by |
| default. |
| |
| =head3 Final classes |
| |
| For final classes, every method is made final, regardless of the method |
| modifier. Final classes must not be inherited from. |
| |
| =head2 Variables |
| |
| Variables are declared with a declaration of the following form: |
| |
| variable-declaration = variable-exposure-specifier? |
| variable-modifier* |
| type variable-name ";" |
| variable-exposure-specifier = "public" |
| variable-modifier = "inert" |
| variable-name = identifier |
| |
| =head3 Inert variables |
| |
| Inert variables are class variables of which only a single copy exists. |
| They are declared in the generated C header with the name |
| C<{parcel_nick}_{Class_Nick}_{Variable_Name}> and must be defined in a C |
| source file. |
| |
| Example: |
| |
| public class Pathfinder::Path { |
| public inert int max_path_length; |
| } |
| |
| This will generate: |
| |
| extern int pfind_Path_max_path_length; |
| |
| The C source file defining the variable will typically use short names. So the |
| definition will look like: |
| |
| int Path_max_path_length = 5000; |
| |
| =head3 Inert variable exposure |
| |
| Inert variables without public exposure have parcel exposure. They are not |
| visible outside of the parcel. |
| |
| =head3 Instance variables |
| |
| Non-inert variables are instance variables and added to the class struct. They |
| must not have an exposure specifier. |
| |
| Example: |
| |
| public class Pathfinder::Path { |
| int num_nodes; |
| |
| public int |
| Get_Num_Nodes(Path *self); |
| } |
| |
| This will add a C<num_nodes> member to struct C<pfind_Path>. To access the |
| member, the macro C<C_PFIND_PATH> must be defined before including the |
| generated header file: |
| |
| #define C_PFIND_PATH |
| #define PFIND_USE_SHORT_NAMES |
| #include "Pathfinder/Path.h" |
| |
| int |
| Path_get_num_nodes(Path *self) { |
| return self->num_nodes; |
| } |
| |
| =head2 Functions |
| |
| function-declaration = function-exposure-specifier? |
| function-modifier* |
| return-type function-name |
| "(" param-list? ")" ";" |
| function-exposure-specifier = "public" |
| function-modifier = "inert" | "inline" | "abstract" | "final" |
| return-type = return-type-qualifier* type |
| return-type-qualifier = "incremented" | "nullable" |
| function-name = identifier |
| param-list = param | param "," param-list |
| param = param-qualifier* type param-name ("=" scalar-constant)? |
| param-name = identifier |
| param-qualifier = "decremented" |
| |
| =head3 Function exposure |
| |
| Functions without public exposure have parcel exposure. They are not |
| visible outside of the parcel. |
| |
| =head3 Inert functions |
| |
| Inert functions are dispatched statically. They are declared in the generated |
| C header with the name C<{parcel_nick}_{Class_Nick}_{Function_Name}> |
| and must be defined in a C source file. They must be neither abstract nor |
| final. |
| |
| Example: |
| |
| public class Pathfinder::Graph::VisibilityGraph nickname VisGraph |
| extends Clownfish::Obj { |
| |
| public inert incremented VisibilityGraph* |
| new(int node_capacity); |
| } |
| |
| This will generate: |
| |
| pfind_VisibilityGraph* |
| pfind_VisGraph_new(int node_capacity); |
| |
| The C source file implementing the inert function will typically use short |
| names. So the implementation will look like: |
| |
| #define PFIND_USE_SHORT_NAMES |
| #include "Pathfinder/Graph/VisibilityGraph.h" |
| |
| VisibilityGraph* |
| VisGraph_new(int node_capacity) { |
| /* Implementation */ |
| } |
| |
| =head3 Inline functions |
| |
| Inert functions can be inline. They should be defined as static inline |
| functions in a C block in the Clownfish header file. The macro C<CFISH_INLINE> |
| expands to the C compiler's inline keyword and should be used for portability. |
| |
| =head3 Methods |
| |
| Non-inert functions are dynamically dispatched methods. Their name must start |
| with an uppercase letter and every underscore must be followed by an uppercase |
| letter. Methods must not be declared inline. |
| |
| The first parameter of a method must be a pointer to an object of the method's |
| class which receives the object on which the method was invoked. By convention, |
| this parameter is named C<self>. |
| |
| For every method, an inline wrapper for dynamic dispatch is defined in |
| the generated C header with the name |
| C<{Parcel_Nick}_{Class_Nick}_{Method_Name}>. Additionally, an |
| implementing function is declared with the name |
| C<{Parcel_Nick}_{Class_Nick}_{Method_Name}_IMP>. The Clownfish compiler also |
| generates a typedef for the method's function pointer type named |
| C<{Parcel_Nick}_{Class_Nick}_{Method_Name}_t>. Wrappers and typedefs are |
| created for all subclasses whether they override a method or not. |
| |
| Example: |
| |
| public class Pathfinder::Graph::VisibilityGraph nickname VisGraph |
| extends Clownfish::Obj { |
| |
| public void |
| Add_Node(VisibilityGraph *self, decremented Node *node); |
| } |
| |
| This will generate: |
| |
| /* Wrapper for dynamic dispatch */ |
| static inline void |
| Pfind_VisGraph_Add_Node(pfind_VisibilityGraph *self, pfind_Node *node) { |
| /* Inline code for wrapper */ |
| } |
| |
| /* Declaration of implementing function */ |
| void |
| Pfind_VisGraph_Add_Node_IMP(pfind_VisibilityGraph *self, |
| pfind_Node *node); |
| |
| /* Declaration of function pointer type */ |
| typedef void |
| (*Pfind_VisGraph_Add_Node_t)(pfind_VisibilityGraph *self, |
| pfind_Node *node); |
| |
| The implementing function of non-abstract methods must be defined in a C source |
| file. This file will typically define the short names macro. So the |
| implementation will look like: |
| |
| #define PFIND_USE_SHORT_NAMES |
| #include "Pathfinder/Graph/VisibilityGraph.h" |
| |
| void |
| VisGraph_Add_Node_IMP(VisibilityGraph *self, Node *node) { |
| /* Implementation */ |
| } |
| |
| =head3 Looking up function pointers |
| |
| Clownfish defines a macro named C<CFISH_METHOD_PTR> that looks up the pointer |
| to the implementing function of a method. The first parameter of the macro is |
| a pointer to the Clownfish::Class object of the method's class, the second is |
| the unshortened name of the method wrapper. If short names for the Clownfish |
| parcel are used, the macro is also available under the name C<METHOD_PTR>. |
| |
| To lookup methods from a superclass, there's a macro C<CFISH_SUPER_METHOD_PTR> |
| with the same parameters. |
| |
| Example using short names: |
| |
| VisGraph_Add_Node_t add_node |
| = METHOD_PTR(PFIND_VISIBILITYGRAPH, Pfind_VisGraph_Add_Node); |
| |
| VisGraph_Add_Node_t super_add_node |
| = SUPER_METHOD_PTR(PFIND_VISIBILITYGRAPH, Pfind_VisGraph_Add_Node); |
| |
| =head3 Abstract methods |
| |
| For abstract methods, the Clownfish compiler generates an implementing function |
| which throws an error. They should be overridden in a subclass. |
| |
| =head3 Final methods |
| |
| Final methods must not be overridden. They must not be abstract. |
| |
| =head3 Nullable return type |
| |
| If a function has a nullable return type, it must return a pointer. |
| Non-nullable functions must never return the NULL pointer. |
| |
| =head3 Incremented return type |
| |
| Incremented return types must be pointers to Clownfish objects. The function |
| will either return a new object with an initial reference count of 1 or |
| increment the reference count. The caller must decrement the reference count of |
| the returned object when it's no longer used. |
| |
| For returned objects with non-incremented return type, usually no additional |
| handling of reference counts is required. Only if an object is returned from an |
| accessor or a collection object and the caller wants to use the object longer |
| than the returning object retains a reference, it must increment the reference |
| count itself and decrement when the object is no longer used. |
| |
| =head3 Decremented parameters |
| |
| Decremented parameters must be pointers to Clownfish objects. The function |
| will either decrement the reference count of the passed-in object or retain a |
| reference without incrementing the reference count. If the caller wants to use |
| the passed-in object afterwards, it usually must increment its reference count |
| before the call and decrement it when it's no longer used. If the caller does |
| not make further use of the passed-in object, it must not decrement its |
| reference count after the call. |
| |
| =head3 Default parameter values |
| |
| Default parameter values can be given as integer, float, or string literals. |
| The values C<true>, C<false>, and C<NULL> are also supported. The default |
| values are only used by the host language bindings. They're not supported |
| when calling a function from C. |
| |
| =head2 C blocks |
| |
| Clownfish headers can contain C blocks which start with a line containing the |
| string C<__C__> and end on a line containing the string C<__END_C__>. The |
| contents of a C block are copied verbatim to the generated C header. |
| |
| Example: |
| |
| __C__ |
| |
| struct pfind_AuxiliaryStruct { |
| int a; |
| int b; |
| }; |
| |
| __END_C__ |
| |
| =head2 Object life cycle |
| |
| =head3 Object creation |
| |
| Objects are allocated by invoking the C<Make_Obj> method on a class's |
| Clownfish::Class object. |
| |
| Any inert function can be used to construct objects from C. But to support |
| inheritance and object creation from the host language, Clownfish classes |
| need a separate function to initialize objects. The initializer must take a |
| pointer to an object as first argument and return a pointer to the same |
| object. If the parent class has an initializer, it should be called first by |
| the subclass's initializer. |
| |
| By convention, the standard constructor is named C<new>. If a class has an |
| inert function named C<init>, it is used as initializer to create a host |
| language constructor by default. |
| |
| Example: |
| |
| /* Clownfish header */ |
| |
| class Vehicle { |
| double max_speed; |
| |
| inert Vehicle* |
| init(Vehicle *self, double max_speed); |
| } |
| |
| class Train inherits Vehicle { |
| double track_gauge; |
| |
| inert incremented Train* |
| new(double max_speed, double track_gauge); |
| |
| inert Train* |
| init(Train *self, double max_speed, double track_gauge); |
| } |
| |
| /* Implementation */ |
| |
| Train* |
| Train_new(double max_speed, double track_gauge) { |
| Train *self = (Train*)Class_Make_Obj(TRAIN); |
| return Train_init(self, max_speed, track_gauge); |
| } |
| |
| Train* |
| Train_init(Train *self, double max_speed, double track_gauge) { |
| Vehicle_init((Vehicle*)self, max_speed); |
| self->track_gauge = track_gauge; |
| return self; |
| } |
| |
| =head3 Reference counting |
| |
| Clownfish uses reference counting for memory management. Objects are created |
| with a reference count of 1. There are two macros C<CFISH_INCREF> and |
| C<CFISH_DECREF> to increment and decrement reference counts. If short names |
| for the Clownfish parcel are enabled, the macros can be abbreviated to |
| C<INCREF> and C<DECREF>. Both macros take a pointer to an object as argument. |
| NULL pointers are allowed. C<CFISH_INCREF> returns a pointer to the object. |
| This value might differ from the passed-in pointer in some cases. So if a |
| reference is retained, the pointer returned from C<CFISH_INCREF> should be |
| used. C<CFISH_DECREF> returns the modified reference count. |
| |
| Examples: |
| |
| self->value = INCREF(arg); |
| |
| DECREF(object); |
| |
| =head3 Object destruction |
| |
| If an object's reference count reaches 0, its C<Destroy> method is called. |
| This public method takes no arguments besides C<self> and has no return value. |
| It should release the resources held by the object and finally call the |
| C<Destroy> method of the superclass via the C<CFISH_SUPER_DESTROY> macro with |
| short name C<SUPER_DESTROY>. This macro takes the C<self> pointer as first |
| argument and a pointer to the object's Clownfish::Class as second argument. |
| The C<Destroy> method of the Clownfish::Obj class will eventually free the |
| object struct. |
| |
| Example: |
| |
| /* Clownfish header */ |
| |
| class Path { |
| VArray *nodes; |
| |
| public void |
| Destroy(Path *self); |
| } |
| |
| /* Implementation */ |
| |
| void |
| Path_Destroy_IMP(Path *self) { |
| DECREF(self->nodes); |
| SUPER_DESTROY(self, PATH); |
| } |
| |
| =head1 COPYRIGHT |
| |
| Clownfish is distributed under the Apache License, Version 2.0, as described |
| in the file C<LICENSE> included with the distribution. |
| |
| =cut |
| |