How to quickly write TCL procs with switches and the like? edit
This is a proposal on how to extend the notation of args in the definition of proc. It is a request for comments, no implementation is available now.
What types of args / switches shall be available? edit
- switches with values, e.g. -start index of lsearch; they do have a default value
- switches without value, e.g. -exact of lsearch; their existence is boolean, false by default
- required named parameters
- optional named parameters with default values
- unnamed optional parameters
How shall these parameters be accessed inside the procedure? edit
Numbered as above...
- switches could be just local variables, e.g. ${-start}
- boolean values of local variables, e.g. ${-exact}
- this is the default
- just like the original implementation
- args is still available to catch the rest
Suggestion edit
Allow extended syntax of
args: This special parameter name comes as a list...
- first item is the keyword args
- items with leading dash are boolean switches (with (1.) or without (2.) default values)
- items without leading dash are named parameters (with (3.) or without (4.) default values)
- items that are a list of two elements are the name and the default value respectively
- the last item can optionally be args again (5.)
Assume an extension to
subst:
proc mysubst {{args -nobackslashes -nocommands -novariables -nocomplain {-uplevel 0} -inplace string1 {string2 {}} args}} {
# the above notation is backward compatible ("default values" of args are currently ignored).
# a redirection of proc could generate the following code:
set -nobackslashes false
set -nocommands false
set -novariables false
set -nocomplain false
set -uplevel 0
set -inplace false
set string2 {}
for {set i 0} {$i < 7} {incr i} {
# 7 is the max number of switches plus their values
set c [lindex $args $i]
if {$c in {-uplevel}} {
# 1. switches with default values
set $c [lindex $args [incr i]]
} elseif {$c in {-nobackslashes -nocommands -novariables -nocomplain -inplace}} {
# 2. boolean switches
set $c true
} else {
if {$c eq {--}} {incr i}
break
}
}
incr i -1 ;# or do not incr in the first line below (which is harder to generate)?
# 3. required (consider errors!)
set string1 [lindex $args [incr i]]
# 4. optional
if {[llength $args] > [incr i]} {set string2 [lindex $args $i]}
# more of the above line can be nested in the then-branch...
# 5. unnamed
set args [lrange $args $i end]
unset i c
# end of generated code - body below
# relative levels are offset by one
catch {incr -uplevel}
# having both string and args is just to demonstrate the possibilities - use args only
if {{} eq $string2} {set args $string1} {set args [list $string1 $string2 {*}$args]}
# TODO implement
# something like the following - use catch if -nocomplain and return unmodified
# also, if -inplace use upvar 1 and modify the values; plus consider a loop for args...
# return [uplevel ${-uplevel} [list ::subst {*}$forward_switches $string]]
# demo output
foreach var {-nobackslashes -nocommands -novariables -nocomplain -uplevel -inplace string1 string2 args} {
puts "$var is {[set $var]}"
}
}
set x 14
set y {$x}
set z {[expr $x * 3]}
subst -nocomplain -inplace x y z
Considerations edit
- the double-dash "--" is always a good idea to protect non-switches starting with a dash
- implementation could happen as proc-redirection or even better natively (just like the interpreter handles optional parameters now!)
- should the generated code be visible in info body?
- the above generated code does not allow parameters with names c or i.
- parameters are switches if and only if their name starts with a dash
See also edit
- [argparse] implements many advanced switch and parameter processing capabilities