Check-in [8b39d1aa17]

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added a 'lost' TIP from Lars Hellström
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8b39d1aa17dee877b712f0c9951e85f3ab171e59172e0d5fed15fc18880b580a
User & Date: dkf 2019-04-14 16:07:26
Context
2019-04-14
16:07
Regenerate the index check-in: 51c5eaa0b1 user: dkf tags: trunk
16:07
Added a 'lost' TIP from Lars Hellström check-in: 8b39d1aa17 user: dkf tags: trunk
15:43
Mark TIPs as Final check-in: 2bb7f8026a user: dkf tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added tip/539.md.














































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# TIP 539: Multiple dict filter patterns
	Author:         Lars Hellström <[email protected]>
	State:          Draft
	Type:           Project
	Vote:           Pending
	Created:        27-Nov-2008
	Post-History:   
	Keywords:       Tcl, dict filter, set intersection
	Tcl-Version:	8.7
	Tcl-Ticket:     2370575
-----

# Abstract

The **key** and **value** forms of **dict filter** are generalised 
to allow an arbitrary number of patterns.

# Rationale

Although there are **dict** subcommands which allow deleting some keys 
from a dictionary (**dict remove**) and inserting some keys into a 
dictionary (**dict replace**), 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).

There is of course already the **dict filter** command, which indeed 
returns a subdictionary of an existing dictionary, but its **key** form 
only accepts one **string match** 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's neither common nor 
particularly readable.) However, in many instances where this kind of 
pattern is used (notably **glob**, **namespace export**, and 
**switch**), it is possible to give several such patterns and have it 
interpreted as the union of the patterns. Were that the case with 
**dict filter**, the "`-foo`, `-bar`, and `-baz`" problem could be solved as 
easily as

    dict filter $opts key -foo -bar -baz

which is comparable to

    dict remove $opts -foo -bar -baz
    dict replace $opts -foo 1 -bar off -baz 42

and much nicer than the **script** counterpart

    dict filter $opts script {key val} {
        ::tcl::mathop::in $key {-foo -bar -baz}
    }

If the **key** form is generalised like this, then it seems appropriate 
to also generalise the **value** form in the same way to keep the 
symmetry, even though I have no immediate use-case for that feature.

Since it is generally good to Do Nothing Gracefully, the command syntax is
also generalised to allow the case of no patterns at all. The result in that
case will be the empty dictionary

# Specification

The two **dict filter** command forms:

 > **dict filter** _dictionary_ **key** _pattern_  
 > **dict filter** _dictionary_ **value** _pattern_

are generalised to accept an arbitrary number of <i>pattern</i>s:

 > **dict filter** _dictionary_ **key** ?_pattern_ …?  
 > **dict filter** _dictionary_ **value** ?_pattern_ …?

and the results are the sub-dictionaries of those keys and values 
respectively which match at least one of the <i>pattern</i>s.

# Rejected Alternatives

A more direct way of meeting the motivating need would be a command 
**dict select** with the same syntax as **dict remove** (no pattern 
matching) but logic reversed. This would however be so close to 
**dict filter** ... **key** that extending the syntax of the latter 
seemed more appropriate.

An alternative to allowing multiple patterns with **dict filter** 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

    dict filter $opts script {key val} {regexp $RE $key}

and on the other it would be rather difficult to read, as the regular 
expression corresponding to "`-foo` or `-bar` or `-baz`" is

    ^(-foo|-bar|-baz)$

which it is tempting but incorrect to simplify to `-foo|-bar|-baz`.

# Implementation Notes

An implementation exists (it's a very trivial to modify **dict filter** 
… **value** to work this way: just add an inner loop over the list of 
patterns); see [patch #2370575](/tcl/tktview/2370575).

What might be tricky is the case of **dict filter** … **key**, 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 
**dict filter** does not guarantee keys in the result to be in the same 
order as in the input dictionary.

Indeed, a **dict filter** … **key** 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:

    set D {-baz 0 -bar 1 -foo 2}
    dict filter $D key -foo -bar *

On the other hand, this effect can mostly be obtained through use of 
**dict merge** already:

    dict merge {-foo x -bar x} $D

# Copyright

This document has been placed in the public domain.