Argument Expansion SyntaxPeter SpjuthDonal K. Fellows$Revision: 1.8 $
This TIP proposes to add syntax in Tcl to perform argument expansion in a safe and efficient manner.
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:
ZXZhbCBkZXN0cm95IFt3aW5mbyBjaGlsZHJlbiAuXQ==
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 something specialised in doing this would be better.
See also . Please also see a summary of a poll of TCLCORE readers taken after was rejected.
For examples three statements are used. This is the eval version:
ZXZhbCBkZXN0cm95IFt3aW5mbyBjaGlsZHJlbiAuXQ==ZXZhbCBidXR0b24gLmIgJHN0ZGFyZ3MgLXRleHQgXCRteXRleHQgLWJkICRib3JkZXI=ZXZhbCBleGVjIFwkcHJvZyAkb3B0czEgW2dldE1vcmVvcHRzXSBcJGZpbGUxIFwkZmlsZTI=
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:
ZXZhbCBleGVjIFwkcHJvZyBbbHJhbmdlICRvcHRzMSAwIGVuZF0gW2xyYW5nZSBbZ2V0TW9yZW9wdHNdIDAgZW5kXSBcJGZpbGUxIFwkZmlsZTI=
With the proposed syntax they become:
ZGVzdHJveSB7fVt3aW5mbyBjaGlsZHJlbiAuXQ==YnV0dG9uIC5iIHt9JHN0ZGFyZ3MgLXRleHQgJG15dGV4dCAtYmQgJGJvcmRlcg==ZXhlYyAkcHJvZyB7fSRvcHRzMSB7fVtnZXRNb3Jlb3B0c10gJGZpbGUxICRmaWxlMg==
The advantage of using syntax for this is that the command do not get obscured. In the examples destroy/button/exec is the most important information on each line and it gets to be first on the line.
If a word starts with a pair of braces, "{}", and is followed by a non whitespace character it signifies argument expansion. The braces are removed and the rest of the word is parsed and substituted as any other word. The character after the removed "{}" counts as a first character in the rules about open braces and double quotes. After substitution, the word is then parsed as a list (as if with Tcl_SplitList() or Tcl_GetListFromObj) and each element of the list is added to the command being built as a separate word with no further parsing.
Before executing the command any word to be expanded is treated as a list where each element becomes one separate argument to the command.
Note 1: A word should really start with {} to trigger expansion which means that words like these are not expanded:
Y21kICJ7fSR0ZW1wIiBce31bc29tZXRoaW5nXQ==
Note 2: Expansion is typically most useful with words like:
Y21kIHt9JHZhciB7fVtzb21lY21kICRhcmddIHt9JGFycihbY21kICRhcmddKQ==
But things like this are also legal:
Y21kIHt9d29yZCB7fSR4LCR5IHt9W2Zvb114eVthcGFdIHt9e2FwYSBiZXBhfQ==
Many of the examples that make this TIP the way it is come from either advanced usage of commands like [exec] or from Tk.
Consider the case where you have lists of options for several external commands that are to be executed together in a pipeline. With expansion it becomes easy to execute such things:
ZXhlYyBwcm9nMSB7fSRvcHRsaXN0MSB8IHByb2cyIHt9JG9wdGxpc3QyIHwgcHJvZzMgLXN0YXRpY09wdGlvbg==
As you can see, without expansion building this pipeline would be quite a complex task and would make what is going on much more obscure.
With Tk, there are many examples. Here's one from the creation of lines on a canvas:
c2V0IGlkIFskY2FudiBjcmVhdGUgcG9seWdvbiB7fSRjb29yZHMgLWZpbGwge30ge30kb3B0cyAtdGFncyB7Zm9vIGJhcn1d
In this case, there is a fair amount of material before the coordinate list, some static options (which act like defaults) between the coords list and the user-supplied options list, and some further options (which act like overrides for semantically-significant bits) after that which need careful space handling. This also demonstrates why having a command with a list of expanding indices is not a good idea, since it is plain to see that ongoing maintenance might place extra non-expanding arguments in various places through the command.
Another example demonstrates why having commands as well as variables expanded is a good idea:
bmFtZXNwYWNlIGV2YWwgbXkgew==ICAgdmFyaWFibGUgZGVmYXVsdHMgew==ICAgICAgLWJnIHdoaXRlICAgICAgLWZnIGJsYWNrICAgfQ==ICAgcHJvYyBlbnRyeSB7cGF0aCBhcmdzfSB7ICAgICAgdmFyaWFibGUgZGVmYXVsdHM=ICAgICAgOjplbnRyeSAkcGF0aCB7fSRkZWZhdWx0cyB7fVtwbGF0Zm9ybU9wdHMgJDo6dGNsX3BsYXRmb3JtKHBsYXRmb3JtKV0ge30kYXJncw==ICAgfQ==fQ==
This illustrates why just plain [concat] doesn't work, demonstrates that having a way to do commands can be very useful, and also shows that having multiple expansion operations in a row is potentially useful.
A final example (deleting discontiguous ranges of characters with a particular tag) shows that this is not just useful in Tk for when creating widgets and canvas items:
JHRleHQgZGVsZXRlIHt9WyR0ZXh0IHRhZyByYW5nZXMgJHRhZ1RvQ2xlYW5VcF0=
In this case, the obvious alternative:
Zm9yZWFjaCB7cyBlfSBbJHRleHQgdGFnIHJhbmdlcyAkdGhlVGFnXSB7ICR0ZXh0IGRlbGV0ZSAkcyAkZSB9
is wrong, because the positions of the tags move with each deletion (by contrast, the [$text delete] operation is careful in this regard.)
This document has been placed in the public domain.