<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE TIP SYSTEM "http://www.tcl.tk/cgi-bin/tct/tip/tipxml.dtd">
<!-- Converted at Thu May 17 04:29:27 GMT 2012 -->
<!-- TIP AutoGenerator - written by Donal K. Fellows -->

<TIP number='341'>
<header><title>Multiple &apos;dict filter&apos; Patterns</title><author address="mailto:Lars.Hellstrom@residenset.net">Lars Hellström</author><status type='project' state='final' tclversion="8.6" vote='after'>$Revision: 1.5 $</status><history></history><created day='27' month='nov' year='2008' /><keyword>Tcl {set intersection}</keyword></header>
<abstract>The <emph style="bold">key</emph> and <emph style="bold">value</emph> forms of <emph style="bold">dict filter</emph> are generalised to allow an arbitrary number of patterns.</abstract>
<body><section title="Specification">
<para>The two <emph style="bold">dict filter</emph> command forms</para>
<quote><emph style="bold">dict filter</emph> <emph style="italic">dictionary</emph> <emph style="bold">key</emph> <emph style="italic">pattern</emph></quote>
<quote><emph style="bold">dict filter</emph> <emph style="italic">dictionary</emph> <emph style="bold">value</emph> <emph style="italic">pattern</emph></quote>
<para>are generalised to</para>
<quote><emph style="bold">dict filter</emph> <emph style="italic">dictionary</emph> <emph style="bold">key</emph> ?<emph style="italic">pattern</emph> ...?</quote>
<quote><emph style="bold">dict filter</emph> <emph style="italic">dictionary</emph> <emph style="bold">value</emph> ?<emph style="italic">pattern</emph> ...?</quote>
<para>and the results are the sub-dictionaries of those keys and values respectively which match at least one of the patterns.</para>
</section>
<section title="Rationale">
<para>Although there are <emph style="bold">dict</emph> subcommands which allow deleting some keys from a dictionary (<emph style="bold">dict remove</emph>) and inserting some keys into a dictionary (<emph style="bold">dict replace</emph>), there is no direct way of requesting the sub-dictionary which only has keys from a given list; if we think of only the set of keys in the dictionary, then we have subcommands for set minus and set union, but none for set intersection. A situation where this would be useful is that the option dictionary for a high-level procedure can contain options meant to be passed on to lower level commands, and it is necessary to extract the subdictionary of options that the lower level command would accept (since passing one which is not supported would cause it to throw an error).</para>
<para>There is of course already the <emph style="bold">dict filter</emph> command, which indeed returns a subdictionary of an existing dictionary, but its <emph style="bold">key</emph> form only accepts one <emph style="bold">string match</emph> pattern and therefore cannot be used to e.g. select all three of -foo, -bar, and -baz (it could select both -bar and -baz through the pattern -ba[rz], but that&apos;s neither common nor particularly readable). However, in many instances where this kind of pattern is used (notably <emph style="bold">glob</emph>, <emph style="bold">namespace export</emph>, and <emph style="bold">switch</emph>), it is possible to give several such patterns and have it interpreted as the union of the patterns. Were that the case with <emph style="bold">dict filter</emph>, the &quot;-foo, -bar, and -baz&quot; problem could be solved as easily as</para>
<verbatim><vline encoding='base64'>ICBkaWN0IGZpbHRlciAkb3B0cyBrZXkgLWZvbyAtYmFyIC1iYXo=</vline></verbatim>
<para>which is comparable to</para>
<verbatim><vline encoding='base64'>ICBkaWN0IHJlbW92ZSAkb3B0cyAtZm9vIC1iYXIgLWJheg==</vline><vline encoding='base64'>ICBkaWN0IHJlcGxhY2UgJG9wdHMgLWZvbyAxIC1iYXIgb2ZmIC1iYXogNDI=</vline></verbatim>
<para>and much nicer than the <emph style="bold">script</emph> counterpart</para>
<verbatim><vline encoding='base64'>ICBkaWN0IGZpbHRlciAkb3B0cyBzY3JpcHQge2tleSB2YWx9IHs=</vline><vline encoding='base64'>ICAgICA6OnRjbDo6bWF0aG9wOjppbiAka2V5IHstZm9vIC1iYXIgLWJhen0=</vline><vline encoding='base64'>ICB9</vline></verbatim>
<para>If the <emph style="bold">key</emph> form is generalised like this, then it seems appropriate to also generalise the <emph style="bold">value</emph> form in the same way to keep the symmetry, even though I have no immediate use-case for that feature.</para>
<para>Since it is generally good to Do Nothing Gracefully, the command syntax is also generalised to allow the case of no patterns at all.</para>
</section>
<section title="Rejected Alternatives">
<para>A more direct way of meeting the motivating need would be a command <emph style="bold">dict select</emph> with the same syntax as <emph style="bold">dict remove</emph> (no pattern matching) but logic reversed. This would however be so close to <emph style="bold">dict filter</emph> ... <emph style="bold">key</emph> that extending the syntax of the latter seemed more appropriate.</para>
<para>An alternative to allowing multiple patterns with <emph style="bold">dict filter</emph> could be to allow a regular expression pattern, since the union of two regular languages is again a regular language. Any syntax that could be picked for that would however on one hand already be rather close to</para>
<verbatim><vline encoding='base64'>ICBkaWN0IGZpbHRlciAkb3B0cyBzY3JpcHQge2tleSB2YWx9IHtyZWdleHAgJFJFICRrZXl9</vline></verbatim>
<para>and on the other it would be rather difficult to read, as the regular expression corresponding to &quot;-foo or -bar or -baz&quot; is</para>
<verbatim><vline encoding='base64'>ICBeKC1mb298LWJhcnwtYmF6KSQ=</vline></verbatim>
<para>which it is tempting but incorrect to simplify to &quot;-foo|-bar|-baz&quot;.</para>
</section>
<section title="Implementation Notes">
<para>An implementation exists (it&apos;s a very trivial to modify <emph style="bold">dict filter</emph> ... <emph style="bold">value</emph> to work this way: just add an inner loop over the list of patterns); see SF path #2370575. [<url ref="https://sourceforge.net/support/tracker.php?aid=2370575"/>]</para>
<para>What might be tricky is the case of <emph style="bold">dict filter</emph> ... <emph style="bold">key</emph>, since this currently has an optimisation for the case of a pattern without glob metacharacters that would be very desirable to keep for the motivating use-case of selecting specific keys from a dictionary. The natural way to do that would be to make the loop over patterns the outer loop and the loop over dictionary entries the inner loop, which is only entered if the current pattern contains metacharacters. Such an optimisation would however have the script-level-visible consequence of having the keys show up in the order of the patterns rather than the order of the original dictionary, so it may be a good idea to also explicitly specify that <emph style="bold">dict filter</emph> does not guarantee keys in the result to be in the same order as in the input dictionary.</para>
<para>Indeed, a <emph style="bold">dict filter</emph> ... <emph style="bold">key</emph> that reorders keys according to its pattern arguments could sometimes be useful in interactive situations, as a way of getting selected keys up from in a dictionary:</para>
<verbatim><vline encoding='base64'>ICBzZXQgRCB7LWJheiAwIC1iYXIgMSAtZm9vIDJ9</vline><vline encoding='base64'>ICBkaWN0IGZpbHRlciAkRCBrZXkgLWZvbyAtYmFyICo=</vline></verbatim>
<para>On the other hand, this effect can mostly be obtained through use of <emph style="bold">dict merge</emph> already:</para>
<verbatim><vline encoding='base64'>ICBkaWN0IG1lcmdlIHstZm9vIHggLWJhciB4fSAkRA==</vline></verbatim>
</section>
<section title="Copyright">
<para>This document has been placed in the public domain. </para>
</section>
</body></TIP>

