TIP #457: Add Support for Named Arguments


TIP:457
Title:Add Support for Named Arguments
Version:$Revision: 1.18 $
Authors: Mathieu Lafon <mlafon at gmail dot com>
Andreas Leitgeb <avl at logic dot at>
State:Draft
Type:Project
Tcl-Version:8.7
Vote:Pending
Created:Monday, 21 November 2016
Keywords:Tcl, procedure, argument handling

Abstract

This TIP proposes an enhancement of the Tcl language to support named arguments and additional features when calling a procedure.

The naming of arguments to procedures is a computer language feature which allow developers to specify the name of an argument when calling a function. This is especially useful when dealing with arguments with default values, as this does not require to specify all previous arguments when only one argument is required to be specified.

As such, this is a commonly requested feature by Tcl developers, who have created various code snippets [1] to simulate it. These snippets have drawbacks: not intuitive for new users, require to add extra code at the start of each procedure, no standard on the format to use, few errors handling, etc.

After discussing various possibilities with the community, it has been decided to extend the argument specification of the proc command and allow users to define options on arguments. This can be used to support named arguments but also add additional enhancements: flag arguments, pass-by-name (upvar) arguments, non-required arguments, ...

The others possibilities discussed are detailed in the Discussion section at the end of the document.

Specification

The proc documentation currently define argument specifiers as a list of one or two fields where the first field is the name of the argument and the optional second field is its default value.

The proposed modification is to support an alternate specifier format where the first field is also the name of the argument, followed by a paired list of options and their values. This format does not prevent the original format to be used as they can be easily distinguished: the new format uses an odd size list with a minimal size of three fields.

Available argument specifiers

The following argument specifiers are defined in this TIP:

Further argument specifiers may be added in future TIP. Examples of new argument specifiers which may be added in the future:

Named arguments

The following rules define how named arguments are expected to be specified on the call-site:

Generated usage description

The error message, automatically generated when the input arguments are invalid, is updated regarding new options:

Introspection

The info argspec command is added to get the argument specification of all arguments or of a specific argument.

% proc p { a { b 1 } { c -name c } } {}
% info argspec p
a { b -default 1 } { c -name c }
% info argspec p c
-name c

Performance

The handling of the new argument specifiers during a proc call has a minimal, but non-null impact on performance. Initial testing on a non-optimized implementation has shown a speed decrease of only 10%-20%, which must be compared to a decrease of nearly 900% when using a Tcl-pure implementation

proc p1 {a b {c 0} {d 0} {e 0} {f 0} {g 0} {h 0}} {
  list $a $b $c $d $e $f $g $h
}
proc p2 {a b args} {
  array set opt [concat {-C 0 -D 0 -E 0 -F 0 -G 0 -H 0} $args]
  list $a $b $opt(-C) $opt(-D) $opt(-E) $opt(-F) $opt(-G) $opt(-H)
}
proc p3 {a b {c -default 0 -name C} {d -default 0 -name D} {e -default 0 -name E} {f -default 0 -name F} {g -default 0 -name G} {h -default 0 -name H}} {
  list $a $b $c $d $e $f $g $h
}
puts "default:  [time {p1 A B 0 0 0 8 0 42} 1000000]"
puts "Tcl-pure: [time {p2 A B -F 8 -H 42}   1000000]"
puts "TIP-457:  [time {p3 A B -F 8 -H 42}   1000000]"
default:  0.604988 microseconds per iteration
Tcl-pure: 5.378907 microseconds per iteration  (+889%)
TIP-457:  0.698328 microseconds per iteration  (+ 15%)

Users with critical requirements on speed should be warned and may prefer not using extended argument specifiers.

The performance of a Tcl-pure procedure defined without any extended argument specifiers is not affected by the modification because the original initialization code is still used in that case.

Implementation

This document proposes the following changes to the Tcl core:

  1. Add ExtendedArgSpec structure which is linked from CompiledLocal and contains information about extended argument specification;

  2. Add a flags field in the Proc structure to later identify a proc with at least one argument defined with an extended argument specification (PROC_HAS_EXT_ARG_SPEC);

  3. Update proc creation to handle the extended argument specification and fill the ExtendedArgSpec structure;

  4. Update InitArgsAndLocals to initialize the compiled locals using a dedicated function if the PROC_HAS_EXT_ARG_SPEC flag has been set on the proc. If unset, the original initialization code is still used.

  5. Update ProcWrongNumArgs to generate an appropriate error message when an argument has been defined using an extended argument specification;

  6. Add info argspec command;

  7. Update documentation in doc/proc.n;

  8. Update impacted tests and add dedicated tests in tests/proc-enh.test.

Reference Implementation

The reference implementation is available in the tip-457 [2] branch.

The code is licensed under the BSD license.

Discussion

This section details some of the envisioned solutions for this feature.

Initial approaches that tried to work with unmodified procedures are not detailed here for clarity.

Dedicated builtin command

A dedicated command can be used to handle the named arguments, using an -option value syntax, before calling the target procedures with all arguments correctly prepared.

% call -opts myproc -optC foo -optB {5 5} -- "some pos arg"

An implementation of this proposal is available at [3]. This proposal was abandoned as it was not enough intuitive for users.

Modification in how proc are defined

Tcl-pure procedures can be defined in a way which state that the procedure will automatically handle -option value arguments.

% proc -np myproc { varA { optB defB } { optC defC } { optD defD } args } { .. }
% myproc -optC foo -optB {5 5} -- "some pos arg"

An other possibility is to support options on arguments and allow name specification:

% proc myproc { varA { optB -default defB -name B } args } { .. }
% myproc a -B b zz

This is the currently proposed solution in this TIP. It requires the procedures to be modified but allow additional features.

Argument Parsing extension

Cyan Ogilvie's paper from Tcl2016 [4] describes a C extension to provide core-like argument parsing at speed comparable to proc argument handling, in a terse and self-documenting way.

Copyright

This document has been placed in the public domain.


Powered by Tcl[Index] [History] [Edit] [HTML Format] [Source Format] [LaTeX Format] [Text Format] [XML Format] [*roff Format (experimental)] [RTF Format (experimental)]

TIP AutoGenerator - written by Donal K. Fellows