Proposal for proc argument handling enhancments

I have viewed TIP#457 [L1 ] and disussions with an eye towards keeping faith with the Tao of Tcl. I've thought about this general issue, and spurred by Cyan Ogilvie's paper, I have come up with the following proposal. I think this proposal is forward compatible with existing scripts and provides for the requirements for: built-in argument pre-parsing, named parameters -ish, and passing by reference or passing arrays or call by name (obviate upvar).

I'm putting this out for discussion. I am not intending to file a TIP since I do not have an implementation nor will be attempting one. The work here might even be best handled by multiple TIP's.

Proposal:

Expand proc arglist definition to accept additional specification details for arguments. Each argument specifier list can be expanded to have additional fields. All additional fields are optional.

  • Use Tk as a model to define the additional fields.
     argname    -- name of argument variable.
     default    -- Default value if actual is not specified.
     optionname -- "flag" name used when specifying argument actual
                   by name
     argtype    -- Type definition
     argclass   -- Name to be used for possible db lookup,
                   or validation, or ...
     flags      -- Examples: NULL_OK, REQUIRED, etc.
     help       -- Brief textual description of argument
  • Types
  • Predefined types
        Boolean  Int   Double   String  Flag
        Array    List  Dict     Ref     Script
  • Tk types
        Anchor   Bitmap   Border  Color   Cursor  Font
        Justify  Pixels   Relief  Synonym Window
  • User defined types: this could be the name of an OO class assumed to have certain methods for validation.
  • The "Flag" type is an option that does not take a value. Either the option is present or it is not. A "Boolean" type is an option that takes a boolean value. "-join" in glob is a "Flag", "-gmt" in clock is a "Boolean".
  • The empty type, "", is treated as a string.
  • Flags
  • NULL_OK -- Tcl does not have nulls, but the closest surrogate would be a variable that does not exist. To demonstrate:
      proc test {
             {f "" -f Font TextFont NULL_OK "Specifies override font (optional)"}
      } {
          if {[info exists f]} {
              puts "Using font $f"
          } else {
              puts "Font is NULL"
          }
      }
  • Extend the Tcl C API call Tcl_CreateObjCommand() to accept an optional args list.
      Tcl_CreateObjCommandEx(interp, cmdName, proc, argsList, clientData, deleteProc)
  • A shorthand for passing arrays: use () to denote an array argument. Any other syntatic sugar has a non-zero chance of breaking existing code. (note: it's not legal currently to use parentheses '()' in an argument name)
      proc find_flightplan_from_position {flightplan() position()} {}
  • For internationalization purposes, consider all hyphen like glyphs to be equivalent when processing options. (- MINUS Unicode: U+002D, UTF-8: 2D; – EN DASH Unicode: U+2013, UTF-8: E2 80 93; — EM DASH Unicode: U+2014, UTF-8: E2 80 94; ‑ NON-BREAKING HYPHEN Unicode: U+2011, UTF-8: E2 80 91)

Example proc with additional argument details:

proc http::register {
     {proto   "" -protocol ""     "" REQUIRED "URL protocol prefix, e.g. https"}
     {port    "" -port     Int    "" REQUIRED "Default port for protocol"}
     {command "" -command  Script "" REQUIRED "Command to use to create socket"}
    } {
    variable urlTypes
    set urlTypes([string tolower $proto]) [list $port $command]
}

bll 2016-11-27 And it would be nice if the option processing/parsing could also be called separately so that command line parameters could be parsed (from argv, from an environment variable, from a configuration file).