Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Updated the tip479 spec to place the new commands for dictargs wrapping in a dedicated namespace and leave room in the spec for handling alternate argument handing schemes |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
16ec396728d2815e014fac117bd96cad |
User & Date: | hypnotoad 2018-10-27 11:04:48.184 |
Context
2018-10-27
| ||
14:42 | Editorial tidy up for TIP 518 check-in: e531f63c61 user: dkf tags: trunk | |
11:04 | Updated the tip479 spec to place the new commands for dictargs wrapping in a dedicated namespace and leave room in the spec for handling alternate argument handing schemes check-in: 16ec396728 user: hypnotoad tags: trunk | |
11:03 | Tip495 revision. check-in: 4304dd5b57 user: hypnotoad tags: trunk | |
Changes
Changes to tip/479.md.
|
| | | 1 2 3 4 5 6 7 8 | # TIP 479: Add Named Procedures as a New Command in Tcl (dictargs::proc) Author: Sean Woods <[email protected]> State: Draft Type: Project Vote: Pending Created: 23-Oct-2017 Post-History: Keywords: Tcl,procedure,argument handling |
︙ | ︙ | |||
31 32 33 34 35 36 37 | option database. Also, those option/value pairs go directly into C data structures, they at no time feed a script with local variables. # Specification Currently if the last parameter named *args* is given a default value, that information is essentially ignored by the workings inside of tclProc.c. This spec calls for storing | | > > > > > > > > > > > | | > | | | | | | | | | | 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 | option database. Also, those option/value pairs go directly into C data structures, they at no time feed a script with local variables. # Specification Currently if the last parameter named *args* is given a default value, that information is essentially ignored by the workings inside of tclProc.c. This spec calls for storing information where a default would go for the args parameter. This information is a list with two fields: *namespace* and *spec*. *namespace* is a Tcl namespace which contains the command *parse*. Parse accepts two arguments, a specification and list containing the contents of *args*. How that specification is interpreted is left to the imagination of the developer. This spec defines a reference implementation called dictargs. # dictargs Under dictargs the specification for non positional arguments is a dict. Each key in the dict will be the name of a local variable that the parameter will populate. The values in the dict will be a key/value set of configuration option for the named parameter system. Developers can specify if a named parameter has a default if not given. They can also specify if the parameter is required. A non-mandatory parameter will not be mapped to a local variable, but it is understood that developers may want to advertise their presence for documentation purposes. proc foo {{{args {dictargs { bar {default: baz} }}}}} { puts $bar } % foo > baz % foo bar bing > bing The primary use case for this tip are new functions that take only named parameters. This TIP also calls for the creation of a new command, provisionally named *dictargs::proc*. _dictargs::proc_ will accept the same number of arguments as _proc_, but the format for the argument spec will be a dict instead of a list. For TclOO methods, we will also create an dictargs::method as a shortcut to: oo::define myclass method namemethod {{{args { bar {default: baz} }}}} { ... } The workings of dictargs::proc and dictargs::method are essentially: proc dictargs::proc {name argspec body} { proc $name [list [list args $argspec]] $body } Named parameters are designed to be deliverable in any order. Named parameters can also be omitted. As such it is necessary to provide more introspection than the current incarnation of **proc** provides. If the procedure requires more than the default behavior or populating local variables with the argumemnt given, it can introspect with **$args** with **\[dict exists\]** to detect if an argument was given at all. The argument spec that was given by the developer will also be available as the local variable **argspec**. % dictargs::proc p {a {default: {}}} { return $args } % p a {} % p foo bar a {} foo bar Given these rules, we can get into non-intuitive failures. For instance, what would happen if a default value was not provided for an argument, and the command call does not provide one. % dictargs::proc q {a {default: {}} b {}} { # Proc assumes b will be given set result [list $a $b] foreach {f v} $args { if {$item ni [dict keys ${argspec}]} { lappend result $item [dict get $args $item] } } } % q error: No such variable b ; # Stack trace points to first use if $b % q b foo bar baz a {} b foo bar baz It would be helpful to have that field (b) treated as a mandatory argument, and have the error thrown in the procedure's argument parser, not in the procedure itself. After some play testing with the rules I have worked out what properties will be tracked for each named parameter, and how those properties are calculated if not specified directly in the options. ## Configuration Options for Dictargs Named Parameters The following general rules apply to all values given in the configuration dict for a named parameter. 1. If a value for any option is given as an empty string, it is inferred to be null. 2. A variable will be created with the same name as the named parameter. 3. A field that is given, but not otherwise reserved by the spec, is ignored by the parser but made available for introspection via the **argspec** dictionary. |
︙ | ︙ | |||
126 127 128 129 130 131 132 | Type: value Default: null When non-null, if a named parameter is missing from the call assume the value specified. Example: | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | Type: value Default: null When non-null, if a named parameter is missing from the call assume the value specified. Example: % dictargs::proc u { a { default: {A useful value} } } { puts $a } % u > A useful value % u a {Less usefull} |
︙ | ︙ | |||
148 149 150 151 152 153 154 | the following rules apply to aliases: 1. If a parameter with the canonical name is given, alternatives will be ignored. 2. If multiple non-canonical parameters are given, the last value given will be the value for the canonical field. Example: | | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | the following rules apply to aliases: 1. If a parameter with the canonical name is given, alternatives will be ignored. 2. If multiple non-canonical parameters are given, the last value given will be the value for the canonical field. Example: % dictargs::proc u { a { default: {A useful value} aliases: {alpha A} } } { puts [list $a $args] } |
︙ | ︙ | |||
181 182 183 184 185 186 187 | This TIP will be rolled out in 3 stages. ## Stage 1 - Pure Tcl (finished) Stage 1 is a pure-tcl implementation to allow the community to try out the rules and see if this new concept is a good fit for Tcl. The implementation will use a macro-like | | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | This TIP will be rolled out in 3 stages. ## Stage 1 - Pure Tcl (finished) Stage 1 is a pure-tcl implementation to allow the community to try out the rules and see if this new concept is a good fit for Tcl. The implementation will use a macro-like template to place the implementation rules as a pre-amble to the body given to dictargs::proc or dictargs::method. This implementation will affect line numbers in traces, but should provide the new features without introducing a major impact on performance. This implementation has been posted to the http://wiki.tcl.tk/49071 and will be kept up to date. ## State 2 - C Extension (finished) |
︙ | ︙ | |||
205 206 207 208 209 210 211 | cd tip479 fossil clone http://fossil.etoyoc.com/fossil/tip479 tip479.fossil fossil open tip479.fossil tclsh make.tcl all ## State 3 - Core patch | | | > < | < < | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | cd tip479 fossil clone http://fossil.etoyoc.com/fossil/tip479 tip479.fossil fossil open tip479.fossil tclsh make.tcl all ## State 3 - Core patch The original specification required modifications to the core. These modifications, while they did not seem to impact normal operations, also did not seem to actually improve performance over the pure-tcl or C compiled extension. The modifications ### TclCreateProc In TclCreateProc, if an named argument spec was registered for the function, additional *localPtr* entries are registered beyond *args* to hold the expected values added by the spec. |
︙ | ︙ | |||
240 241 242 243 244 245 246 | named argument spec registered. If a spec was present, after it performs its normal population of local variable matching the parameters for the procedure, the function calls *ProcEatArgs* which pairs key/value pairs beyond the last positional parameter with registered name parameters (and their associated local variable. ### init.tcl | | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | named argument spec registered. If a spec was present, after it performs its normal population of local variable matching the parameters for the procedure, the function calls *ProcEatArgs* which pairs key/value pairs beyond the last positional parameter with registered name parameters (and their associated local variable. ### init.tcl Two macros for dictargs::proc and dictargs::method are placed in the init.tcl file to ensure those facilities are present at runtime. The community is presently in a debate as to whether seperate commands are the best approach, or modifying proc and oo::define::method to accept flags is better. ### info argspec In the info namespace, add an *argspec* command to return the named argument spec for |
︙ | ︙ | |||
301 302 303 304 305 306 307 | } ## Extra Metadata for argument handling The standard only defines the behavior for several properties for parameters, but does not prohibit storing additional properties. Consider: | | | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | } ## Extra Metadata for argument handling The standard only defines the behavior for several properties for parameters, but does not prohibit storing additional properties. Consider: dictargs::proc prettyproc { color { comment: {Color of the button} type: color default: green } flavor { comment: {What flavor candy emerges when pressed.} |
︙ | ︙ | |||
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | if {$flavor ni $flavors} { error "Invalid flavor $flavor. Valid: random OR $flavors" } } } # Spec Revisions 2017-11-03 - Renamed @proc to procx, @args to argsx and @method to methodx. Removed the internal variable @spec from bodies. Added 2017-10-28 - Removed the *variable* option. The core implementation really needs a canonical name for the variable in the index. If a user really wants a different name in the arguments, we have the aliases facility. Also clarified that this tip will be modifying how a default for the args parameter is interpreter and | > > > > > > > > > > > | | 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 | if {$flavor ni $flavors} { error "Invalid flavor $flavor. Valid: random OR $flavors" } } } # Spec Revisions 2018-10-19 - Replaced the idea that this tip would be providing the only means of named argument parsing with the concept that this tip would provide the shims for developers to provide such a mechanism, as well as provide a reference implementation called "dictargs". Renamed procx to dictargs::proc and methodx to dictargs::method, and clarified that argument parsing will be performed by dictargs::parse Removed the core patches, and instead casting this TIP as an information one for developers who wish to either exploit dictargs or utilize their own non-positional argument processing scheme. 2017-11-03 - Renamed @proc to procx, @args to argsx and @method to methodx. Removed the internal variable @spec from bodies. Added 2017-10-28 - Removed the *variable* option. The core implementation really needs a canonical name for the variable in the index. If a user really wants a different name in the arguments, we have the aliases facility. Also clarified that this tip will be modifying how a default for the args parameter is interpreter and that procx and methodx are just convenience wrappers. |