TIP:            103
Title:          Argument Expansion Command
Version:        $Revision: 1.13 $
Author:         Peter Spjuth <peter.spjuth@space.se>
Author:         Donal K. Fellows <donal.k.fellows@man.ac.uk>
Author:         Andreas Leitgeb <avl@logic.at>
State:          Rejected
Type:           Project
Vote:           Done
Created:        15-Jun-2002
Post-History:   
Tcl-Version:    8.5

~ Abstract

This TIP proposes to add a command that can perform argument expansion
in a safe and efficient manner.

~ Introduction

Many commands take a variable number of arguments and often you find
yourself with those arguments in a list.  This list must then be
expanded into individual arguments to the command.  This is currently
done with eval:

|eval destroy [winfo children .]

This is a bit obscure and also very error prone when the command
becomes more complex.  It is also inefficient and not object safe, why
a command specialised in doing this would be better.

~ Rationale

There have been suggestions of introducing some new syntax to Tcl to
handle argument expansion.  That is a big and controversial step, and
not anything this TIP wants to meddle in.  A command can improve every
point where eval has shortcomings and thus give a good result with
less means.  It can also serve as a bridge to a future global syntax.

Such a command can be done in several ways and below the choice in
this TIP's specification is defended.

As examples three statements are used which will be repeated for
different alternatives.  This is the eval version:

|eval destroy [winfo children .]
|eval button .b $stdargs -text \$mytext -bd $border
|eval exec \$prog $opts1 [getMoreopts] \$file1 \$file2

The eval version would be even more complex if the lists that are to
be expanded are not known to be pure. To be really safe the last
would be:

|eval exec \$prog [lrange $opts1 0 end] [lrange [getMoreopts] 0 end] \$file1 \$file2

With the proposed command they become:

|expand { destroy `[winfo children .] }
|expand { button .b `$stdargs -text $mytext -bd $border }
|expand { exec $prog `$opts1 `[getMoreopts] $file1 $file2 }

An alternative to having a local syntax is to point at the arguments
that should be expanded, either by index:

|expand {end} destroy [winfo children .]
|expand {2} button .b $stdargs -text $mytext -bd $border
|expand {2 3} exec $prog $opts1 [getMoreopts] $file1 $file2

Or by some flag mechanism:

|expand destroy + [winfo children .]
|expand button .b + $stdargs -text - $mytext -bd $border
|expand exec - $prog + $opts1 + [getMoreopts] - $file1 - $file2

Those lack in writability/readability/maintainability in a disturbing
manner.

For the choice of local syntax one goal is that it should not
violate Tcl's rules, which simplifies implementation since Tcl's
parser can do the job.

Any char that fulfils that could be used but the choice fell on ` for
forward compatibility reasons.  See below.

An alternative syntax could be using enclosing `` or some
other enclosing construct like:

|expand { destroy <[winfo children .]> }
|expand { button .b <$stdargs> -text $mytext -bd $border }
|expand { exec $prog <$opts1> <[getMoreopts]> $file1 $file2 }

Paired characters are good for delimiting things.  Here is the
beginning; here is the end.  But this is not about a new way to
delimit things.  It is about indicating a boolean choice:  expand
or do not expand a word into multiple words.  Whatever character
is chosen to be that indicator, it should be a single, leading
one.  No pairs.

In the specification a restrictive rule was chosen that makes
it an error to use ` in a way that do not fit.  This is to make
it easier to change things in the future should ideas come up
for new features.  E.g., should this become a global syntax
in Tcl 9.0 it can be chosen a bit differently and be backward
compatible with the expand command.

~ Specification

A new command "expand" is added.  It takes one argument, which
contains a Tcl script consisting of one command.  The script may
contain comments but only one command is permitted.

The command is processed in the following manner:

 1. Parse into words according to Tcl's standard rules.

 2. Any word starting with ` must be followed by a single variable
    or command substitution.  The word is remembered and the ` is
    removed.

 3. Perform Tcl's normal execution steps on the new line up to the
    point where the command should have been called.

 4. Expand the arguments that should be expanded.

 5. Execute the command.

The return value of expand is the return value of the command.

''Note 1:'' A word should really start with ` to trigger expansion
which means that words like these are not expanded:

|cmd "`$temp" \`[something]

''Note 2:'' Expansion is only performed with words like:

|cmd `$var `[somecmd $arg] `$arr([cmd $arg])

Words like these are a syntax error:

|cmd `word` `$x,$y `[foo]xy[apa]

~ Forward compatibility

One aspect of choosing a syntax here is to think about the
future.  Should there later be a wish for a global syntax for argument
expansion it would be nice if it were the same as the one chosen in
the expand command.  If an agreement
can be made for what may be acceptable in the future, this should
affect the specification in this TIP.

If a single character like ` is chosen for a global expand syntax
it means a backwards compatibility break.  So, what chars
are likely to be used by people and thus causing problems or confusion
when backwards compatibility is broken?

Some food for thought about different chars:

|_     # Word char
|:     # Gets ugly with namespace qualifiers:  :$::var

|!   if !$var {...}
|*   string match *$suffix $line
|^   regexp ^$prefix $line
|~   cd ~$user
||   open |$prog
|.   button .$w ; glob -nocomplain .$str
|=   wm geometry .e =$geo
|@   .x conf -bitmap @$bmp -cursor @$cur
|<   bind . <$left>  ; set html <$tag>

|(   expr ($a + $b) * $c ;# Confuses paren-matching
|)     # Odd enough as opening, but would confuse any paren-matching

|+   expr $a +$b  ;# Same for any operator
|-   
|%
|&   
|?
|/   open /$path   

|'     # Makes more sense as enclosing?
|`     # Makes more sense as enclosing?
|>   exec foobar >/some/file
|,   append recipients ,[join $header($ccL) ,]

|{}  completely forward-compatible, as {} currently cannot be
|    trailed by anything but whitespace. (This would limit the
|    originally proposed global syntax change to the argument
|    of the expand command)

Example usage of those that seem reasonable:

|expand { exec $prog '$opts1 '[getMoreopts] $file1 $file2 }
|expand { exec $prog `$opts1 `[getMoreopts] $file1 $file2 }
|expand { exec $prog ,$opts1 ,[getMoreopts] $file1 $file2 }

For comparison, the syntax that has been proposed earlier that
would not break backwards compatibility:

|expand { exec $prog {}$opts1 {}[getMoreopts] $file1 $file2 }
|expand { exec $prog {expand}$opts1 {expand}[getMoreopts] $file1 $file2 }

~ Discussion

When first issued the TIP caused some discussion on c.l.t.  Until a
summary is made, here is the thread:

http://groups.google.com/groups?th=9e77d5836b06ab1b

Another thread about it:

http://groups.google.com/groups?th=2ba287be87c2678c

~ Reference Implementation

Patch #570201

http://sourceforge.net/tracker/index.php?func=detail&aid=570201&group_id=10894&atid=310894

~ Copyright

This document has been placed in the public domain.
