There are several pages on the wiki regarding different methods for argument parsing and its cousin, named arguments. This page is for general discussions regarding a potential system that might satisfy both of those. Here we can toss back and forth general design questions, key concerns being: - Which feels the most TCL-like - Which might sacrifice some freedom for power One that I've been working on here and there uses a prefix notation in the proc definition for the named argument system to know what to do with. For instance: proc foo { fname o_lname } { puts "$fname" } foo "Richard" -lname "Pryor" Here, the lname is understood by a wrapping proc to be "switchable", and the proc also understands that fname is a required argument, and should not be "named". What do people feel about similar ideas to expand the proc definitions? Another idea is to implement some sort of enumerated definition in the proc "e_actiontype", where actiontype might be defined, maybe within the proc body, or a central location. ---- ''[escargo] 19 Sep 2005'' - I think it might be fruitful to consider why there are so many implementations of argument processing. * What are the underlying problems to be solved by centralizing argument processing? * What are advantages and disadvantages of the different implementations? Using one body of code to process arguments levies certain requirements. 1. There must be a way of specifying the arguments and how they are processed. 1. There must be a way of specifying what to do with arguments that are not recognized. 1. There must be a way of returning the results of processing arguments. 1. There might be a way of returning arguments that are not processed. I have seen some systems where there is an explicit grammar that specifies command arguments; each command can hand off a string containing its argument description in that grammar to an argument parsing service. ---- ''[IL] 19 Sep 2005'' - I think you've summarized the goals well. I'd note with all of tcl's nice introspection capabilities, one could probably fashion a general handler, instead of hardcoding the relationship to the underlying proc. For myself, I'd love a system that can enables a user to have a light encapsulation around user defined procs that emulates the tcl commands. For instance: proc parse args {} { } proc parse_html_links { o_all o_img o_href html } { } could be invoked in the tcl command way, and be understand as being part of a "parse" command set. The first definition could be the router/service. set links [parse html links -all -href $html] set link [parse html links -img $html] This has several advantages over using the default tcl proc system: * It allows for a readable, definable packaging system but with a generalized implementation * The syntax allows for easy modification of the internals by decoupling argument order and required parameters ''[NEM] 19 Sep 2005'': I'm not a big fan of the o_ prefix, or the _ convention. The first looks a bit like Hungarian notation, and the latter is already served by :: and the new ''[namespace ensemble]'' in 8.5. Regarding argument parsing and named arguments, I'd prefer a simple option-parsing command that takes a list of parameters in the same form that proc does, along with a list of arguments and returns a dictionary of the values, or an error if some parameter has not been specified. e.g.: proc person args { set details [option parse {name age {weight 100} {shoesize 10}} $args] dict with details { .... } } person -name "Neil" -age 24 ("option" is unfortunately a Tk command, though). That seems like the best separation of concerns: doesn't force anybody to use it; can be selectively applied to groups of arguments; and can be wrapped into a higher-level construct easily enough. I would prefer it if the command parsed arguments such that any parameter could be specified either positionally or using -name value syntax (although the first positional argument turns off the -name value parsing). The behaviour could then mimick current proc-style parsing by default (something I've needed on occassion), but also then handle named arguments. e.g.: proc apply {lambda args} { lassign $lambda params body set d [option parse $params $args] dict with d $body } set cmd [list {a b {c 12}} { expr ($a*$b)/$c }] apply $cmd 1 2 apply $cmd 2 4 10.0 apply $cmd -a 12 15 24 ;# a=12, b=15, c=24 The ability to specify any parameter using the named form is useful for currying when arguments may be accepted in the wrong order. [escargo] - Maybe there are '''three''' different contexts in which argument parsing occurs: 1. Shell-level (command prompt) commands that communicate with [Tcl] scripts as system executables. 1. Script-level commands that try to look like shell-level commands. 1. Script-level commands that try to look like [Tcl] proc invocations. I have implemented command parsing (shell-level) that tried to allow for either command line or graphical control. There was metadata associated with each command parameter so that the command parser could generate either a text-based or graphical interface to get operator inputs. Flag parameters: Flag name, description. On a command line expected something like -D or nothing; for a GUI generated a checkbox. Enumerated parameters: Parameter name, description, list of legal values. On a command line expected something like -param ''value'' where ''value'' had to be one of the list of legal values; for a GUI generated a radio button group. Value parameters: Parmeter name, description, type information. On a command line expected something like -param ''value'' where ''value'' had to conform to the type information; for a GUI generated a entry widget that called a validator using the type information. Part of the metadata is whether the argument is optional or not; for file names, metadata including information about whether the file had to already exist or not (or didn't matter). Parameters could also be considered to be required. There could also be specification of default values. (Usually I have seen parameters with default values to be optional. Required parameters are of course not optional.) Some parameters were ''list'' parameters, where there was no preceding parameter name. Typically these were lists of file names (usually one or more). I see help in argument parsing to be of most use for 1 and 2. I'm not quite sure why one would want to use it for the 3rd case. [NEM] To handle defaults and "args" correctly. I think it is also important to separate out matching of arguments to (named) parameters and then checking that those parameters fit some constraints/type. These two concerns are best handled by entirely separate procedures, in my opinion. I also tend to avoid boolean -foo arguments (without a matching value), partly for consistency, but also because they don't always stay as simple boolean options. Providing a command-line application interface (e.g., like GNU tools do) is application- and platform-specific. The syntax for specifying command line options is different between Windows and UNIX, for instance. Best to concentrate on a standard syntax for specifying arguments to Tcl commands (based on that of Tk widgets). There is already the cmdline package in tcllib for shell option parsing. ''[escargo]'' - It is useful to point out where there are differences in syntax for command line options; however, that might be an argument (forgive the possible confusion) for hiding some of the details of actual argument processing from the Tcl program. Rather than exactly specifying its arguments, if they are specified in a portable way, the implementation of the argument processing could handle [Unix] vs. [Microsoft Windows] details without the program itself needed to be changed. [NEM] Again, I'd say that is better handled by separate commands. If you separate out value checking from the actual parsing then there will probably be very little common code between Windows, Unix and Tk-style argument parsers. You could layer a higher-level construct over the top, but I think the basic usage of an argument parser should be something like: set data [check $types [option parse $params $args]] Where "option parse" can be replaced by a Windows or UNIX command-line style parser, or some other parser. A higher- level construct for command-line processing could simply switch on $tcl_platform(platform) and choose an appropriate parser, but the basic API should still be available (to avoid the high-level command becoming another kitchen-sink/clock scan). ''[escargo]'' - Personally, I think it's a mistake to separate out parameter value checking from option parsing. When I was generating command-line vs GUI value solicitation, I was able to use the type checking information as tool-tips ([balloon help]) for the GUI. If value checking had been separate, I would not have been able to do that. [NEM] Why? You can easily associate type information with parameters outside of the argument parsing framework. Indeed, the definition of "check" in my last example would fairly depend on it. Just to be clear, here is a more complete example of what I am suggesting: proc person {args} { # Parameter names, positions and optional default values set params {name age {weight 100} {shoesize 10}} # Mapping from parameter names to "types" set types {name string age integer weight integer shoesize integer} # Parse arguments using position/default info set values [option parse $params $args] # Check types using some type-checking routine type check $types $values } Note that both $types and $values are dictionaries using parameter name as key. So you could easily do: proc describe {types values param} { return "$param = [dict get $values $param] : [dict get $types $param]" } You don't need to shove everything into a monolithic structure or process to be able to associate things. ---- [MAK] - As for why there are so many argument parsing schemes, different opinions about how they should be done, and why certain things aren't done by some, argument parsing systems are an abstraction. Abstractions leak. The greater the abstraction the greater the leak. Suggested reading: The Law of Leaky Abstractions [http://www.joelonsoftware.com/articles/LeakyAbstractions.html]. [NEM] The way to minimise the leak is to design your abstractions in small pieces and in layers. If one layer leaks it should be a short drop down to the next layer where the problem can be dealt with. Hence my desire to separate argument parsing from argument validation (or type checking). Then, when you build a higher-level abstraction on top of it (which, as you say, will leak) then you still have some useful components with which to build an alternative solution. In terms of Joel's essay: let's build an IP layer before we build TCP on top. ---- [PWQ] ''21 Sept 05'' I don't know why people get carried away with argument parsing and config file formats. It's totally unproductive and doesnt represent the way scripting languages are designed. I use associative arrays for argument processing. Why? because one command does it all, the syntax for accessing an array is clean and simple, most of my other data is in arrays. You want nested arguments, no problem, just treat the array variable as another array. While dictionarys in 8.5+ are similar they lack the simple referencing via $ that arrays have. Why do you want to create stupid libraries of code when one simple command parses the arguments for you. Want to read a config file?, three lines of code: set f [open configfile r] array set Options [read $f] close $f You people have too much time on your hands, or you are not actually creating any worth while applications. Sure it has limitations, but who cares. It's more important to accept a less flexible argument format and get on with the job of coding rather than spending hours allowing 100 different calling conventions. Lastly, what about error detection?, again this is simple and doable. But having argument checking is just an excuse for failing to test your code adequately. If a procedure takes a number between 1 and 5, you should not need the routine to tell you that you have passed the number 6 to it in error. Your testing methodology should have prevented you from getting that far. And don't forget that since we are ''Scripting'' you can always instrument code as part of the testing regiment automagically. ---- [Category Argument Processing] | [Category Discussion]