/ story-22-Docstrings.org
story-22-Docstrings.org
1 #+TITLE: Story 22 - Docstrings 2 #+OPTIONS: author:nil date:nil 3 #+LANGUAGE: en 4 #+CATEGORY: core 5 6 Docstrings are present in certain programming languages, such as Common Lisp 7 and Python. C doesn't have that concept, but C libraries can certainly 8 implement them, and applications could use them in diverse ways! 9 10 In Le'Sec Core, there are the items where it would be obvious to add 11 docstrings: 12 13 - plugins 14 - data sets 15 - parameter descriptors. 16 17 Another thing that needs to be considered is how the docstrings are to be made 18 available. The obvious choices are: 19 For all those cases, there's a question revolving around how to make a 20 docstring available. There are essentially two ways: 21 22 - make the docstring directly available (i.e. a ~const char *~). 23 - make the docstring available through a function call. 24 25 Exploring this in more depth: 26 27 - Plugins :: 28 29 There isn't much that Le'Sec Core can do here, since all the parts of 30 plugins are handled by the calling application. The only thing that Le'Sec 31 Core can do is to recommend a symbol name for it in dynamically loadable 32 plugins, alongside ~LSC_plugin_start~ and ~LSC_plugin_stop~, perhaps this, 33 for example: 34 35 ~LSC_plugin_docstring~ 36 37 - as a constant string pointer: 38 39 #+begin_src C 40 LSC_EXPORT const char LSC_plugin_docstring[]; 41 #+end_src 42 43 - as a function passing back the docstring: 44 45 #+begin_src C 46 LSC_EXPORT LE_STATUS LSC_plugin_docstring(const char **docs); 47 #+end_src 48 49 - Data Sets :: 50 51 Every Data Set (Object, Operation, ...) could potentially be documented with 52 docstrings. 53 54 - as a constant string pointer: 55 56 That's an added field in the Data Set structure itself. This would be 57 fine, but it has consequences, most of all on the registration functions, 58 which will have to have another argument for the docstring: 59 60 #+begin_src C 61 typedef LE_STATUS LSC_do_all_{name}_implementation_callback_fn 62 (const char *class, const char *id, 63 const LSC_plugin_t *plugin, const LSC_env_t *env, 64 LSC_{name}_dispatch_fn *dispatch_function, 65 LSC_{name}_destroy_fn *destroy_function, 66 const void *dispatch_data, 67 const char *docstring, /* <-- Added argument */ 68 void *user_arg); 69 static inline LE_STATUS LSC_register_{name}_implementation 70 (LSC_env_t *env, LSC_plugin_t *plugin, const char *id, 71 LSC_{name}_dispatch_fn *dispatch_function, 72 LSC_{name}_destroy_fn *destroy_function, 73 const void *dispatch_data, 74 const char *docstring); /* <-- Added argument */ 75 static inline LE_STATUS LSC_deregister_{name}_implementation 76 (LSC_env_t *env, LSC_plugin_t *plugin, const char *id, 77 LSC_{name}_dispatch_fn *dispatch_function, 78 LSC_{name}_destroy_fn *destroy_function, 79 const void *dispatch_data, 80 const char *docstring); /* <-- Added argument */ 81 static inline LE_STATUS LSC_find_{name}_implementation 82 (LSC_env_t *env, const char *id, LSC_plugin_t **plugin, 83 LSC_{name}_dispatch_fn **dispatch_function, 84 LSC_{name}_destroy_fn **destroy_function, 85 const void **dispatch_data, 86 const char **docstring); /* <-- Added argument */ 87 #+end_src 88 89 - as a function passing back the docstring: 90 91 That's an added public function: 92 93 #+begin_src C 94 static inline LE_STATUS 95 LSC_get_{name}_docstring(LSC_{name}_t *lsc_data_set, 96 const char **lsc_docstring); 97 #+end_src 98 99 That's also an extra case for plugin implementors to handle: 100 101 #+begin_src C 102 case LSC_NR_get_docstring: 103 lsc_status = LE_STS_ERROR; 104 { 105 void **lsc_docstring = va_arg(lsc_valist, void **); /* Result */ 106 if (lsc_docstring == NULL) 107 break; /* TODO: Set more precise status */ 108 109 ,*lsc_docstring = "..."; 110 } 111 lsc_status = LE_STS_SUCCESS; 112 break; 113 #+end_src 114 115 - Param descriptors :: 116 117 - as a constant string pointer: 118 119 This would be an added field in ~LSC_param_desc_t~. 120 121 - as a function passing back the docstring: 122 123 There are two possibilities: 124 125 - get the docstrings in an array, indexed by parameter identity: 126 127 #+begin_src C 128 typedef struct LSC_param_docstring_st { 129 uint8_t p_id; 130 const char *p_docstring; 131 } LSC_param_docstring_t; 132 133 static inline LE_STATUS 134 LSC_get_gettable_{name}_param_docstrings 135 (LSC_{name}_t *o, const LSC_param_docstring_t **docstrings); 136 137 static inline LE_STATUS 138 LSC_get_settable_{name}_param_docstrings 139 (LSC_{name}_t *o, const LSC_param_docstring_t **docstrings); 140 #+end_src 141 142 - get the docstring separately for each parameter: 143 144 #+begin_src C 145 static inline LE_STATUS 146 LSC_get_gettable_{name}_param_docstring 147 (LSC_{name}_t *o, unsigned int param_num, 148 const LSC_param_docstring_t **docstrings); 149 150 static inline LE_STATUS 151 LSC_get_settable_{name}_param_docstring 152 (LSC_{name}_t *o, unsigned int param_num, 153 const LSC_param_docstring_t **docstrings); 154 #+end_src 155 156 As can be seen, not matter of docstrings are directly available as strings 157 pointers, or are available through a function call, there are breaking 158 changes, and there is added churn. 159 160 /There are also other considerations to be made./ 161 162 A goal is for the Data Set structure to be permanently fixed at some point, no 163 more changes allowed, at least as far as Le'Sec Core and plugins are concerned. 164 Every added field comes with a worry that this isn't the end, that more may be 165 coming. It's also been a long while since the last change (the dispatch data 166 addition), so this can feal like quite an upheaval. 167 168 That being said, if the function call option is chosen, that's a lot of added 169 churn for applications and plugin implementations, especially with docstrings 170 for parameter descriptors, which may also be undesirable. 171 172 The decision on which route to choose is left to the implementation and 173 experimentation.