| 134 | |
| 135 | === 2. Reglas de acceso a miembros === |
| 136 | |
| 137 | * 2.1. Para acceder a los miembros públicos se usará el nombre del NameBlock con el operador especial |
| 138 | |
| 139 | |
| 140 | Anything nameblock_id::public_member_id |
| 141 | |
| 142 | Siguiendo con el ejemplo del punto 1.2 anterior: |
| 143 | {{{ |
| 144 | Real MyNS_1.2::_.exported_1; |
| 145 | Real MyNS_1.2::_.exported_2; |
| 146 | Real MyNS_1.2::fun_a(MyNS_1.2::_.exported_1); |
| 147 | Set table = |
| 148 | [[ |
| 149 | MyNS_1.2::mystr(1,"uno"), |
| 150 | MyNS_1.2::real2mystr(4.0), |
| 151 | MyNS_1.2::real2mystr(Pi) |
| 152 | ]]; |
| 153 | }}} |
| 154 | * 2.2. Evidentemente no se puede acceder con :: a los miembros privados. Ejemplo de uso inválido: |
| 155 | {{{ |
| 156 | Real MyNS_1.2::_aux_1; |
| 157 | Real MyNS_1.2::_fun_aux(1); |
| 158 | }}} |
| 159 | * 2.3. En ningún caso es posible acceder a los miembros públicos ni privados de un NameBlock mediante los operadores de acceso a Set Set[Real], Set[Text],y aún menos con Set->field_name puesto que no puede existir un NameSpace con estructura. Ejemplo de uso inválido: |
| 160 | {{{ |
| 161 | Real MyNS_1.2[3]; |
| 162 | Real MyNS_1.2["exported_2"]; |
| 163 | Real BadNS_2.3->x_; |
| 164 | }}} |
| 165 | * 2.4. Nótese que el concepto de miembro se extiende tan sólo a los elementos a primer nivel del conjunto base de un NameBlock, y no al resto de elementos de su jerarquía recursiva de subconjuntos aunque tengan nombre accesible desde el nivel del conjunto. |
| 166 | Ejemplo de uso inválido: |
| 167 | {{{ |
| 168 | NameBlock MyNS_2.4 = |
| 169 | [[ |
| 170 | Set a = [[ Real a1 = 1; Real a2 = 2 ]] |
| 171 | ]]; |
| 172 | Real MyNS_2.4::a1; |
| 173 | }}} |
| 174 | |
| 175 | === 3. Reglas de anidación === |
| 176 | |
| 177 | * 3.1. Para poder acceder de modo recursivo a los NameBlock's, estos pueden estar anidados como en este nuevo. Ejemplo: |
| 178 | {{{ |
| 179 | NameBlock MyNS_3.1 = |
| 180 | [[ |
| 181 | NameBlock a = [[ Real a1 = 1; Real a2 = 2 ]] |
| 182 | ]]; |
| 183 | Real MyNS_3.1::a::a1; |
| 184 | }}} |
| 185 | * 3.2. Un modo especialmente práctico que puede ayudar a la organización del código sería usar el Include como en el siguiente ejemplo 3.2 |
| 186 | {{{ |
| 187 | //Fichero ns1.tol |
| 188 | ... |
| 189 | |
| 190 | NameBlock NS1 = [[ |
| 191 | Real _aux_1 = 1; |
| 192 | Real _aux_2 = 2; |
| 193 | Real a = _aux_1+_aux_2; |
| 194 | Real b = _aux_1-_aux_2 |
| 195 | ]]; |
| 196 | ... |
| 197 | |
| 198 | //Fichero ns2.tol |
| 199 | ... |
| 200 | NameBlock NS2 = [[ |
| 201 | Real _fun_aux(Real x) { x*4 }; |
| 202 | Real fun_a(Real x) { _fun_aux(x)+1 }; |
| 203 | Real fun_b(Real x) { _fun_aux(x)-1 } |
| 204 | ]]; |
| 205 | ... |
| 206 | |
| 207 | //Fichero MyNS_3.2.tol |
| 208 | NameBlock MyNS_3.2 = |
| 209 | [[ |
| 210 | //Private: |
| 211 | Set _ns1 = Include("ns1.tol"); |
| 212 | Set _ns2 = Include("ns2.tol"); |
| 213 | //Public: |
| 214 | NameBlock NS1; |
| 215 | NameBlock NS2 |
| 216 | ]]; |
| 217 | }}} |
| 218 | Obsérvese que sólo se publican NS1y NS2 por lo que cualquier cosa definida en ns1.tol y ns2.tol distinta de ellos permanecerá inaccesible externamente. |
| 219 | * 3.3. Para mayor comodidad se puede renombrar externamente un NameBlock anidado con un alias identificativo más corto que la concatenación completa de NameBlock's, como se ha visto en el punto 1.1.3. Esto evita tener que escribir demasiados nombres largos que dificulten la lectura. Pero se debe usar siempre de forma cuidadosa, cuando no dé lugar a ambigüedades y siempre en código de usuario final, nunca en librerías de funciones de uso general, pues en tal caso destruye los principios de organización y modularidad que es uno de los principales objetivos de NameBlock. |
| 220 | |
| 221 | En un programa concreto de usuario que va a hacer uso intensivo de un NameBlock de nombre muy largo se podría considear razonable crear un alias como por ejemplo: |
| 222 | {{{ |
| 223 | NameBlock _aia = std::math::stat::model::mle::arima::aia; |
| 224 | }}} |
| 225 | |
| 226 | === 4. Reglas de publicación o globalización === |
| 227 | |
| 228 | * 4.1.En determinadas circunstancias los miembros públicos o de sólo lectura de un NameBlock pueden pasar al ámbito global, es decir, se puede acceder a ellos sin explicitarlo con ::. A este hecho se le llamará publicar un NameBlock y se logra con el operador Real UsingNameBlock(NameBlock nameblock_idt) y es similar al using namespace de C++, aunque con ciertas diferencias. |
| 229 | * 4.2.El operador UsingNameBlock devuelve cierto si es compatible con el resto de variables de tipo NameBlock actualmente globalizadas, es decir, si no contiene ningún miembro público con el mismo nombre que otro. Los miembros que ya estuvieran presentes no serán accesibles de forma implícita pero sí mediante ::, y se mostrará un mensaje de aviso para advertirlo. |
| 230 | * 4.3.Como es lógico, este operador de globalización no surte efecto si se llama en ambiente local, lo cual incluye dentro de un NameBlock, y devolverá falso y un mensaje de error si se intenta. |
| 231 | * 4.4.El NameBlock permanecerá en uso mientras siga existiendo el objeto devuelto por este operador. Por ejemplo, si se ha incluido en un fichero estará presente hasta que se descompile dicho fichero. |
| 232 | * 4.5.Si existe una variable global previa con el mismo nombre ocultará el miembro NameBlock publicado que seguirá siendo accesible con ::, como es lógico. Si se crea la variable global posteriormente se actuará del mismo modo. |
| 233 | * 4.6.Se trata de una sentencia no declarativa sino ejecutiva por lo que no tiene efecto si se recupera de un módulo OIS. |
| 234 | * 4.7.Al igual que con los alias del apartado 3.3., se debe ser sumamente cauteloso con este tipo de sentencias y no incluirlas en librerías de caracter general. Sería prudente usarlas sólo en programas de usuario final y cuando no haya ninguna posible ambigüedad de nomenclatura. Puede ser particularmente útil para mantener compatibilidad hacia atrás de código creado previamente a la existencia de NameBlock. |
| 235 | |
| 236 | === 5. Reglas de ámbito === |
| 237 | Un NameBlock tiene su propia tabla de símbolos que se usa cuando está activo, es decir, cuando se está ejecutando alguna de sus funciones miembro. Sólo puede haber activo un NameBlock al mismo tiempo o bien no haber ninguno activo en cuyo caso todo funciona como hasta ahora. El orden de búsquedas de símbolos de TOL que anteriormente se reducía a símbolos de ámbito local y ámbito global, pasa a ser el siguiente: |
| 238 | |
| 239 | * 5.1. Miembro local: Si hay un NameBlock activo se busca ahí. |
| 240 | * 5.2. Ámbito local: Si no lo había o bien no contiene el nombre buscado y estamos en ambiente local se busca en la pila local. |
| 241 | * 5.3. Ámbito global: Si aún no se ha encontrado nada en los dos puntos anteriores se busca en la tabla global de símbolos. |
| 242 | * 5.4. Miembro publicado: Si sigue sin encontrarse el símbolo se buscará en la tabla de NameBlock publicados. |
| 243 | |
| 244 | Cuando se llama a una función de un NameBlock se activa el mismo y la búsqueda de variables, funciones y estructuras locales le da total prioridad a los miembros de ese NameBlock de forma que se pueden usar todos ellos, tanto públicos como privados. |
| 245 | |
| 246 | Esto reduce el uso actual de scope dinámico en la pila local de llamadas de funciones, lo cual puede ayudar a medio plazo a reconducir a los usuarios de TOL a los estándares de programación. |
| 247 | |
| 248 | === Ventajas === |
| 249 | |
| 250 | Las ventajas que aportan los NameBlock's se pueden resumir en que da facilidades para alcanzar mayor modularidad, mejor organización y legibilidad y mayor reusabilidad del código. |
| 251 | |
| 252 | ==== Modularidad ==== |
| 253 | |
| 254 | La principal utilidad del NameBlock es dotar a TOL de un mecanismo de modularidad más allá del fichero que permita construir módulos, paquetes y librerías robustamente organizados. Una forma prudente de anidar los NameBlock's sería en este caso: lib_id::package_id::module_id |
| 255 | Legibilidad |
| 256 | Pero un NameBlock podría también ayudar a la legibilidad del código en tareas más humildes, al sustituir llamadas a set[num_field] por set::name_field sin el coste computacional añadido de set["name_field"] y sin tener que definir estructuras de datos espúreas para usar set->name_field |
| 257 | Eliminación de variables globales |
| 258 | Un caso especialmente recomendable es el que afecta a todos los parámetros de configuración y variables globales en general que deberían incluirse dentro de un único NameBlock global para evitar colisiones de nombres. |
| 259 | |
| 260 | //Parámetros de configuración del proyecto |
| 261 | NameBlock cfg = |
| 262 | [[ |
| 263 | //Configuración del acceso a la base de datos |
| 264 | NameBlock db = [[Text alias, Text user, Text pwd, Text host, ...]], |
| 265 | //Configuración de los directorios más utilizados |
| 266 | NameBlock path = [[Text source, Text data, Text log, ...]], |
| 267 | ... |
| 268 | ]]; |
| 269 | Real DBOpen(cfg::db::alias, cfg::db::user, cfg::db::pwd); |
| 270 | |
| 271 | ==== Flexibilidad ==== |
| 272 | |
| 273 | Las funciones que devuelven conjuntos heterogéneos también ganarían flexibilidad, expresibilidad y facilidad de mantenimiento y uso sin recurrir a la definición de estructuras locales |
| 274 | |
| 275 | NameBlock my_stats(Serie ser) |
| 276 | {[[ |
| 277 | Real num = CountS (ser); |
| 278 | Real avg = AvrS(ser); |
| 279 | Real stdv = StDsS(ser) |
| 280 | ]]}; |
| 281 | |
| 282 | NameBlock stats = my_stats(SubSer(Gaussian(0,1,C),y2000,y2000m12d31)); |
| 283 | Real stats::stdv; |
| 284 | |
| 285 | Aunque se añadan elementos a lo que devuelve la función o se reordenen los mismos seguirá funcionando el código que usara esta función accediendo con :: mientras no se cambien los nombres: |
| 286 | |
| 287 | NameBlock my_stats(Serie ser) |
| 288 | {[[ |
| 289 | Real num = CountS (ser); |
| 290 | Real avg = AvrS(ser); |
| 291 | Real mdn = MedianS(ser); |
| 292 | Real stdv = StDsS(ser) |
| 293 | ]]}; |
| 294 | |
| 295 | ==== Generación automática de documentación ==== |
| 296 | A efectos de generación automática de documentación de un NameBlock, se cuenta con la función Set Members(NameBlock root) que devuelve un listado de los miembros públicos contenidos en un NameBlock y sus hijos de forma recursiva, con un registro para cada uno con la siguiente estructura informativa ordenada de la forma natural indicada por los propios campos: |
| 297 | {{{ |
| 298 | Struct NameBlockInfoStruct |
| 299 | { |
| 300 | Text nameBlock_, //full name block path a::b::... |
| 301 | Text mode_, //"Variable", "Function" or "Struct" |
| 302 | Text grammar_, //"Real", "Text", "Set", "NameBlock", ... |
| 303 | Text memberName_, //Internal public member name |
| 304 | Text filePath_, //Relative path to the root file path |
| 305 | Text description_ //User description |
| 306 | }; |
| 307 | }}} |
| 308 | ===== Miembros de documentación accesibles de sólo lectura ===== |
| 309 | Son miembros de sólo lectura de la forma _.autodoc.<sufix> |
| 310 | |
| 311 | * _.autodoc.description: Si un NameBlock contiene un miembro privado Text _.autodoc.description, entonces su contenido pasa a ser la descripción del NameBlock sin necesidad de usar la función PutDescription. |
| 312 | * _.autodoc.keys: Si un NameBlock contiene un miembro privado Set _.autodoc.keys, entonces sus elementos, que han de ser todos de tipo Text, pasan a ser palabras claves utilizadas en los procedimientos de búsqueda temática. |
| 313 | * _.autodoc.url: Si un NameBlock contiene un miembro privado Text _.autodoc.url este se usará en los mecanismos de generación automática para enlazar a la URL especificada en la que se explicará de forma más detallada el funcionamiento del NameBlock. |
| 314 | * _.autodoc.authors: Si un NameBlock contiene un miembro privado Set _.autodoc.authors este se usará en los mecanismos de generación automática para identificar a los autores del código. |
| 315 | |
| 316 | ===== Funciones de información relacionadas ===== |
| 317 | |
| 318 | * Text GetNameBlock(Anything obj): Devuelve el nombre completo del NameBlock al que pertenece un objeto. Si no pertenece a ninguno devuelve la cadena vacía "". |
| 319 | * Text FullName(Anything obj): Devuelve el nombre completo de un objeto, incluyendo el prefijo de su NameBlock si está dentro de uno. |
| 320 | |
| 321 | |