Check-in [adcf227f66]

Login

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

Overview
Comment:Editorial cleanup in 342
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: adcf227f666763e58cd481cdef872a60d59e30c06f1b9728c058f525051a88a8
User & Date: dkf 2019-04-01 07:32:57.529
Context
2019-04-01
20:43
Update 224 to reflect changing opinions of what is valued, in preparation for voting check-in: 3f564e60cd user: dkf tags: trunk
07:32
Editorial cleanup in 342 check-in: adcf227f66 user: dkf tags: trunk
2019-03-31
15:37
Editorial tweaks: [chan pipe] exists check-in: bbf42295f7 user: dkf tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to tip/342.md.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	Post-History:	
	Tcl-Ticket:     2370575
-----

# Abstract

A new subcommand of **dict** is proposed, which returns a dictionary value
if it exists and returns a per-call default otherwise.

# Specification

The **dict** command will get a new subcommand

 > **dict getwithdefault** _dictionary_ _key_ ?_key_ ...?  _value_








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	Post-History:	
	Tcl-Ticket:     2370575
-----

# Abstract

A new subcommand of **dict** is proposed, which returns a dictionary value
if it exists, and a specified-per-call default otherwise.

# Specification

The **dict** command will get a new subcommand

 > **dict getwithdefault** _dictionary_ _key_ ?_key_ ...?  _value_

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
   * It takes time proportional to the size of the dictionary, even when only
     one value is inspected. Since **dict filter key** has an optimisation
     for this kind of situation, there are apparently maintainers which
     consider such differences relevant.

   * The "one **dict merge** early providing defaults for all keys" approach
     cannot deal with keys that have dynamic defaults, e.g. that the default
     for option -foo is the effective value of option -bar.

Hence although **dict merge** is sometimes appropriate for providing
defaults, it is not a universal solution.

The basic approach is instead to, as in the **dict\_getwithdefault** proc
above, first use **dict exists** and then **dict get** if the value
existed. Problems with this approach are:

   * It is redundant: already **dict exists** retrieves the value, but
     doesn't return it, so **dict get** has to look it up all over again.

   * It is bulky: if the value in dictionary _D_ of option **-apa** \(or
     its default **bar**\) is to be passed as an argument to the command
     **foo**, then the complete command is

		     foo [if {[dict exists $D -apa]} then {dict get $D -apa}\
		       else {return -level 0 bar}]

	   > or 

		     foo [expr {[dict exists $D -apa] ? [dict get $D -apa] : "bar"}]

	   > which many programmers would find objectionable. The **dict
     getwithdefault** counterpart is merely

		     foo [dict getwithdefault $D -apa bar]

The only way to avoid the redundance of an extra look-up seems to be to
combine **dict get** with **catch**, like so:

	  if {[catch {dict get $D -apa} value]} then {set value bar} else {set value}

but this has the disadvantage of hiding other sources of error, such as _D_
not being a dictionary in the first place. This kind of error in a normal
processing path is also considered poor style by some.










## Implementation Choices

Even if it is deemed appropriate to have a dedicated subcommand of **dict**
for this, it could be argued that it needn't be part of the compiled Tcl core;
since **dict** is an ensemble, anyone can extend it at the script level and
"the core can do without this bloat". However, it turns out than an in-core







|















|
|

|

|

|


|




|




>
>
>
>
>
>
>
>
>







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
   * It takes time proportional to the size of the dictionary, even when only
     one value is inspected. Since **dict filter key** has an optimisation
     for this kind of situation, there are apparently maintainers which
     consider such differences relevant.

   * The "one **dict merge** early providing defaults for all keys" approach
     cannot deal with keys that have dynamic defaults, e.g. that the default
     for option `-foo` is the effective value of option `-bar`.

Hence although **dict merge** is sometimes appropriate for providing
defaults, it is not a universal solution.

The basic approach is instead to, as in the **dict\_getwithdefault** proc
above, first use **dict exists** and then **dict get** if the value
existed. Problems with this approach are:

   * It is redundant: already **dict exists** retrieves the value, but
     doesn't return it, so **dict get** has to look it up all over again.

   * It is bulky: if the value in dictionary _D_ of option **-apa** \(or
     its default **bar**\) is to be passed as an argument to the command
     **foo**, then the complete command is

		foo [if {[dict exists $D -apa]} then {dict get $D -apa}\
		    else {return -level 0 bar}]

     or 

		foo [expr {[dict exists $D -apa] ? [dict get $D -apa] : "bar"}]

     which many programmers would find objectionable. The **dict
     getwithdefault** counterpart is merely

		foo [dict getwithdefault $D -apa bar]

The only way to avoid the redundance of an extra look-up seems to be to
combine **dict get** with **catch**, like so:

	if {[catch {dict get $D -apa} value]} then {foo bar} else {foo $value}

but this has the disadvantage of hiding other sources of error, such as _D_
not being a dictionary in the first place. This kind of error in a normal
processing path is also considered poor style by some.

An alternate version with **try** fixes that problem... but is ugly:

	try {
	    set value [dict get $D -apa]
	} trap {TCL LOOKUP DICT} {} {
	    set value bar
	}
	foo $value

## Implementation Choices

Even if it is deemed appropriate to have a dedicated subcommand of **dict**
for this, it could be argued that it needn't be part of the compiled Tcl core;
since **dict** is an ensemble, anyone can extend it at the script level and
"the core can do without this bloat". However, it turns out than an in-core
129
130
131
132
133
134
135
136
137
138
139
140
141
142
A script-level implementation is certainly possible, but the minute details of
producing core-looking error messages in this case appears considerable both
compared to the functional parts of the command and compared to the amount of
code needed to do it in the core.

# Reference Implementation

An implementation is provided on SF, in patch \#2370575.
<https://sourceforge.net/support/tracker.php?aid=2370575> 

# Copyright

This document has been placed in the public domain. 








|
<





138
139
140
141
142
143
144
145

146
147
148
149
150
A script-level implementation is certainly possible, but the minute details of
producing core-looking error messages in this case appears considerable both
compared to the functional parts of the command and compared to the amount of
code needed to do it in the core.

# Reference Implementation

An implementation is provided, in [patch #2370575](https://core.tcl-lang.org/tcl/tktview/2370575).


# Copyright

This document has been placed in the public domain.